Compare commits

...

105 Commits

Author SHA1 Message Date
mertalev 03c820931e commit json 2025-07-30 19:53:55 -04:00
mertalev 6cea779b2d optimizations 2025-07-30 19:30:42 -04:00
wuzihao051119 196f2a72f4 temporary change for stress test 2025-07-30 11:37:38 -04:00
wuzihao051119 7f9bc092ac remove locked and favorite 2025-07-30 11:37:38 -04:00
wuzihao051119 dc807777d6 clean code 2025-07-30 11:37:38 -04:00
wuzihao051119 6ad2e8e155 remove ref listen and global key 2025-07-30 11:37:38 -04:00
wuzihao051119 e6c46fe0bf chore: rename 2025-07-30 11:37:38 -04:00
wuzihao051119 749582b6d8 fix: refresh timeline by key 2025-07-30 11:37:38 -04:00
wuzihao051119 94c073e58f perf: do not filter markers 2025-07-30 11:37:38 -04:00
wuzihao051119 5d722eef98 refactor: map query 2025-07-30 11:37:38 -04:00
wuzihao051119 d308d023c2 feat(mobile): drift map page 2025-07-30 11:37:38 -04: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
1250 changed files with 49546 additions and 50136 deletions
@@ -11,8 +11,8 @@ services:
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules - open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
- server_node_modules:/workspaces/immich/server/node_modules - server_node_modules:/workspaces/immich/server/node_modules
- web_node_modules:/workspaces/immich/web/node_modules - web_node_modules:/workspaces/immich/web/node_modules
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload - ${UPLOAD_LOCATION}/photos:/data
- ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload - ${UPLOAD_LOCATION}/photos/upload:/data/upload
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
database: database:
@@ -13,8 +13,8 @@ services:
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules - open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
- server_node_modules:/workspaces/immich/server/node_modules - server_node_modules:/workspaces/immich/server/node_modules
- web_node_modules:/workspaces/immich/web/node_modules - web_node_modules:/workspaces/immich/web/node_modules
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/usr/src/app/upload - ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/usr/src/app/upload/upload - ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/data/upload
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
immich-web: immich-web:
+4 -4
View File
@@ -122,17 +122,17 @@ jobs:
IS_MAIN: ${{ github.ref == 'refs/heads/main' }} IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
run: | run: |
if [[ $IS_MAIN == 'true' ]]; then if [[ $IS_MAIN == 'true' ]]; then
flutter build apk --release --flavor production flutter build apk --release
flutter build apk --release --flavor production --split-per-abi --target-platform android-arm,android-arm64,android-x64 flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
else else
flutter build apk --debug --flavor production --split-per-abi --target-platform android-arm64 flutter build apk --debug --split-per-abi --target-platform android-arm64
fi fi
- name: Publish Android Artifact - name: Publish Android Artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: release-apk-signed name: release-apk-signed
path: mobile/build/app/outputs/flutter-apk/**/*.apk path: mobile/build/app/outputs/flutter-apk/*.apk
- name: Save Gradle Cache - name: Save Gradle Cache
id: cache-gradle-save id: cache-gradle-save
+3 -3
View File
@@ -50,7 +50,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # 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). # 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) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 uses: github/codeql-action/autobuild@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
# ️ Command-line programs to run using the OS shell. # ️ 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 # 📚 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 # ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
with: with:
category: '/language:${{matrix.language}}' category: '/language:${{matrix.language}}'
+3 -3
View File
@@ -90,7 +90,7 @@ jobs:
env: env:
CHANGED_FILES: ${{ steps.verify-changed-files.outputs.changed_files }} CHANGED_FILES: ${{ steps.verify-changed-files.outputs.changed_files }}
run: | 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}" echo "Changed files: ${CHANGED_FILES}"
exit 1 exit 1
@@ -98,7 +98,7 @@ jobs:
run: dart analyze --fatal-infos run: dart analyze --fatal-infos
- name: Run dart format - name: Run dart format
run: dart format lib/ --set-exit-if-changed run: make format
- name: Run dart custom_lint - name: Run dart custom_lint
run: dart run custom_lint run: dart run custom_lint
@@ -129,7 +129,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file - name: Upload SARIF file
uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
with: with:
sarif_file: results.sarif sarif_file: results.sarif
category: zizmor category: zizmor
+1 -1
View File
@@ -668,7 +668,7 @@ jobs:
contents: read contents: read
services: services:
postgres: postgres:
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:1f5583fe3397210a0fbc7f11b0cec18bacc4a99e3e8ea0548e9bd6bcf26ec37a image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:ec713143dca1a426eba2e03707c319e2ec3cc9d304ef767f777f8e297dee820c
env: env:
POSTGRES_PASSWORD: postgres POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres POSTGRES_USER: postgres
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
exit 1 exit 1
fi fi
- name: Find Pull Request - 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 id: find-pr
with: with:
branch: chore/translations branch: chore/translations
+2 -21
View File
@@ -7,7 +7,7 @@
"restart": true, "restart": true,
"port": 9231, "port": 9231,
"name": "Immich API Server", "name": "Immich API Server",
"remoteRoot": "/usr/src/app", "remoteRoot": "/usr/src/app/server",
"localRoot": "${workspaceFolder}/server" "localRoot": "${workspaceFolder}/server"
}, },
{ {
@@ -16,27 +16,8 @@
"restart": true, "restart": true,
"port": 9230, "port": 9230,
"name": "Immich Workers", "name": "Immich Workers",
"remoteRoot": "/usr/src/app", "remoteRoot": "/usr/src/app/server",
"localRoot": "${workspaceFolder}/server" "localRoot": "${workspaceFolder}/server"
},
{
"name": "Flavor - Production",
"request": "launch",
"type": "dart",
"codeLens": {
"for": [
"run-test",
"run-test-file",
"run-file",
"debug-test",
"debug-test-file",
"debug-file",
],
"title": "${debugType}",
},
"args": [
"--flavor", "production"
],
} }
] ]
} }
+77 -77
View File
@@ -1,12 +1,12 @@
{ {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.72", "version": "2.2.73",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.72", "version": "2.2.73",
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
"chokidar": "^4.0.3", "chokidar": "^4.0.3",
@@ -27,13 +27,13 @@
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/micromatch": "^4.0.9", "@types/micromatch": "^4.0.9",
"@types/mock-fs": "^4.13.1", "@types/mock-fs": "^4.13.1",
"@types/node": "^22.16.4", "@types/node": "^22.16.5",
"@vitest/coverage-v8": "^3.0.0", "@vitest/coverage-v8": "^3.0.0",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"cli-progress": "^3.12.0", "cli-progress": "^3.12.0",
"commander": "^12.0.0", "commander": "^12.0.0",
"eslint": "^9.14.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-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^59.0.0", "eslint-plugin-unicorn": "^59.0.0",
"globals": "^16.0.0", "globals": "^16.0.0",
@@ -54,14 +54,14 @@
}, },
"../open-api/typescript-sdk": { "../open-api/typescript-sdk": {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.135.3", "version": "1.136.0",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
"@oazapfts/runtime": "^1.0.2" "@oazapfts/runtime": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.16.4", "@types/node": "^22.16.5",
"typescript": "^5.3.3" "typescript": "^5.3.3"
} }
}, },
@@ -1365,17 +1365,17 @@
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz",
"integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==", "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/type-utils": "8.37.0", "@typescript-eslint/type-utils": "8.38.0",
"@typescript-eslint/utils": "8.37.0", "@typescript-eslint/utils": "8.38.0",
"@typescript-eslint/visitor-keys": "8.37.0", "@typescript-eslint/visitor-keys": "8.38.0",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^7.0.0", "ignore": "^7.0.0",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@@ -1389,7 +1389,7 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.37.0", "@typescript-eslint/parser": "^8.38.0",
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <5.9.0" "typescript": ">=4.8.4 <5.9.0"
} }
@@ -1405,16 +1405,16 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz",
"integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==", "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/typescript-estree": "8.38.0",
"@typescript-eslint/visitor-keys": "8.37.0", "@typescript-eslint/visitor-keys": "8.38.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -1430,14 +1430,14 @@
} }
}, },
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz",
"integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.37.0", "@typescript-eslint/tsconfig-utils": "^8.38.0",
"@typescript-eslint/types": "^8.37.0", "@typescript-eslint/types": "^8.38.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -1452,14 +1452,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz",
"integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/visitor-keys": "8.37.0" "@typescript-eslint/visitor-keys": "8.38.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1470,9 +1470,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz",
"integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -1487,15 +1487,15 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz",
"integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==", "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/typescript-estree": "8.38.0",
"@typescript-eslint/utils": "8.37.0", "@typescript-eslint/utils": "8.38.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
@@ -1512,9 +1512,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz",
"integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -1526,16 +1526,16 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz",
"integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.37.0", "@typescript-eslint/project-service": "8.38.0",
"@typescript-eslint/tsconfig-utils": "8.37.0", "@typescript-eslint/tsconfig-utils": "8.38.0",
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/visitor-keys": "8.37.0", "@typescript-eslint/visitor-keys": "8.38.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@@ -1581,16 +1581,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz",
"integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.7.0", "@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/typescript-estree": "8.37.0" "@typescript-eslint/typescript-estree": "8.38.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1605,13 +1605,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz",
"integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"eslint-visitor-keys": "^4.2.1" "eslint-visitor-keys": "^4.2.1"
}, },
"engines": { "engines": {
@@ -2367,9 +2367,9 @@
} }
}, },
"node_modules/eslint-config-prettier": { "node_modules/eslint-config-prettier": {
"version": "10.1.5", "version": "10.1.8",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
"integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -2383,9 +2383,9 @@
} }
}, },
"node_modules/eslint-plugin-prettier": { "node_modules/eslint-plugin-prettier": {
"version": "5.5.1", "version": "5.5.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz",
"integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==", "integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3548,15 +3548,15 @@
} }
}, },
"node_modules/prettier-plugin-organize-imports": { "node_modules/prettier-plugin-organize-imports": {
"version": "4.1.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.2.0.tgz",
"integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", "integrity": "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"prettier": ">=2.0", "prettier": ">=2.0",
"typescript": ">=2.9", "typescript": ">=2.9",
"vue-tsc": "^2.1.0" "vue-tsc": "^2.1.0 || 3"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"vue-tsc": { "vue-tsc": {
@@ -4139,16 +4139,16 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz",
"integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==", "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.37.0", "@typescript-eslint/eslint-plugin": "8.38.0",
"@typescript-eslint/parser": "8.37.0", "@typescript-eslint/parser": "8.38.0",
"@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/typescript-estree": "8.38.0",
"@typescript-eslint/utils": "8.37.0" "@typescript-eslint/utils": "8.38.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.72", "version": "2.2.73",
"description": "Command Line Interface (CLI) for Immich", "description": "Command Line Interface (CLI) for Immich",
"type": "module", "type": "module",
"exports": "./dist/index.js", "exports": "./dist/index.js",
@@ -21,13 +21,13 @@
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/micromatch": "^4.0.9", "@types/micromatch": "^4.0.9",
"@types/mock-fs": "^4.13.1", "@types/mock-fs": "^4.13.1",
"@types/node": "^22.16.4", "@types/node": "^22.16.5",
"@vitest/coverage-v8": "^3.0.0", "@vitest/coverage-v8": "^3.0.0",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"cli-progress": "^3.12.0", "cli-progress": "^3.12.0",
"commander": "^12.0.0", "commander": "^12.0.0",
"eslint": "^9.14.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-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^59.0.0", "eslint-plugin-unicorn": "^59.0.0",
"globals": "^16.0.0", "globals": "^16.0.0",
+30 -30
View File
@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates. # Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" { provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.52.0" version = "4.52.1"
constraints = "4.52.0" constraints = "4.52.1"
hashes = [ hashes = [
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=", "h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=", "h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=", "h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=", "h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=", "h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=", "h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=", "h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=", "h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=", "h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=", "h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=", "h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=", "h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=", "h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=", "h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0", "zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8", "zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238", "zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f", "zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f", "zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8", "zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9", "zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060", "zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6", "zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb", "zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b", "zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380", "zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7", "zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
] ]
} }
@@ -5,7 +5,7 @@ terraform {
required_providers { required_providers {
cloudflare = { cloudflare = {
source = "cloudflare/cloudflare" source = "cloudflare/cloudflare"
version = "4.52.0" version = "4.52.1"
} }
} }
} }
+30 -30
View File
@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates. # Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" { provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.52.0" version = "4.52.1"
constraints = "4.52.0" constraints = "4.52.1"
hashes = [ hashes = [
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=", "h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=", "h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=", "h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=", "h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=", "h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=", "h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=", "h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=", "h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=", "h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=", "h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=", "h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=", "h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=", "h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=", "h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0", "zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8", "zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238", "zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f", "zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f", "zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8", "zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9", "zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060", "zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6", "zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb", "zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b", "zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380", "zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7", "zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
] ]
} }
+1 -1
View File
@@ -5,7 +5,7 @@ terraform {
required_providers { required_providers {
cloudflare = { cloudflare = {
source = "cloudflare/cloudflare" source = "cloudflare/cloudflare"
version = "4.52.0" version = "4.52.1"
} }
} }
} }
+3 -3
View File
@@ -29,8 +29,8 @@ services:
volumes: volumes:
- ../server:/usr/src/app/server - ../server:/usr/src/app/server
- ../open-api:/usr/src/app/open-api - ../open-api:/usr/src/app/open-api
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload - ${UPLOAD_LOCATION}/photos:/data
- ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload - ${UPLOAD_LOCATION}/photos/upload:/data/upload
- /usr/src/app/server/node_modules - /usr/src/app/server/node_modules
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
env_file: env_file:
@@ -123,7 +123,7 @@ services:
database: database:
container_name: immich_postgres 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_file:
- .env - .env
environment: environment:
+2 -2
View File
@@ -20,7 +20,7 @@ services:
context: ../ context: ../
dockerfile: server/Dockerfile dockerfile: server/Dockerfile
volumes: volumes:
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload - ${UPLOAD_LOCATION}/photos:/data
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
env_file: env_file:
- .env - .env
@@ -63,7 +63,7 @@ services:
database: database:
container_name: immich_postgres 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_file:
- .env - .env
environment: environment:
+2 -2
View File
@@ -18,7 +18,7 @@ services:
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding # service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes: 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 # 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 - /etc/localtime:/etc/localtime:ro
env_file: env_file:
- .env - .env
@@ -56,7 +56,7 @@ services:
database: database:
container_name: immich_postgres 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: environment:
POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME} POSTGRES_USER: ${DB_USERNAME}
+1 -1
View File
@@ -180,7 +180,7 @@ services:
... ...
volumes: 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 # 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 - /etc/localtime:/etc/localtime:ro
+ - originals:/usr/src/app/originals + - originals:/usr/src/app/originals
... ...
+7 -10
View File
@@ -94,19 +94,16 @@ Change media location
``` ```
immich-admin change-media-location immich-admin change-media-location
? Enter the previous value of IMMICH_MEDIA_LOCATION: /usr/src/app/upload ? Enter the previous value of IMMICH_MEDIA_LOCATION: /data
? Enter the new value of IMMICH_MEDIA_LOCATION: /data ? Enter the new value of IMMICH_MEDIA_LOCATION: /my-data
...
Previous value: /data
Current value: /my-data
Previous value: /usr/src/app/upload Changing database paths from "/data/*" to "/my-data/*"
Current value: /data
Changing database paths from "/usr/src/app/upload/*" to "/data/*"
? Do you want to proceed? [Y/n] y ? Do you want to proceed? [Y/n] y
Database file paths updated successfully! 🎉 Database file paths updated successfully! 🎉
...
You may now set IMMICH_MEDIA_LOCATION=/data and restart!
(please remember to update applicable volume mounts e.g. ${UPLOAD_LOCATION}:/data)
``` ```
+13
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`. 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 ## 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. 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.
+5 -3
View File
@@ -58,7 +58,7 @@ Internally, Immich uses the [glob](https://www.npmjs.com/package/glob) package t
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. 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 #### Troubleshooting
@@ -72,7 +72,9 @@ In rare cases, the library watcher can hang, preventing Immich from starting up.
### Nightly job ### 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 ## Usage
@@ -91,7 +93,7 @@ The `immich-server` container will need access to the gallery. Modify your docke
```diff title="docker-compose.yml" ```diff title="docker-compose.yml"
immich-server: immich-server:
volumes: volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload - ${UPLOAD_LOCATION}:/data
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro + - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
+ - /home/user/old-pics:/mnt/media/old-pics:ro + - /home/user/old-pics:/mnt/media/old-pics:ro
+ - /mnt/media/videos:/mnt/media/videos:ro + - /mnt/media/videos:/mnt/media/videos:ro
+6 -6
View File
@@ -27,11 +27,11 @@ After defining the locations of these files, we will edit the `docker-compose.ym
services: services:
immich-server: immich-server:
volumes: volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload - ${UPLOAD_LOCATION}:/data
+ - ${THUMB_LOCATION}:/usr/src/app/upload/thumbs + - ${THUMB_LOCATION}:/data/thumbs
+ - ${ENCODED_VIDEO_LOCATION}:/usr/src/app/upload/encoded-video + - ${ENCODED_VIDEO_LOCATION}:/data/encoded-video
+ - ${PROFILE_LOCATION}:/usr/src/app/upload/profile + - ${PROFILE_LOCATION}:/data/profile
+ - ${BACKUP_LOCATION}:/usr/src/app/upload/backups + - ${BACKUP_LOCATION}:/data/backups
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
``` ```
@@ -44,7 +44,7 @@ docker compose up -d
:::note :::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. 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. 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.
+77 -47
View File
@@ -12,118 +12,148 @@ Run `docker exec -it immich_postgres psql --dbname=<DB_DATABASE_NAME> --username
## Assets ## Assets
### Name
:::note :::note
The `"originalFileName"` column is the name of the file at time of upload, including the extension. The `"originalFileName"` column is the name of the file at time of upload, including the extension.
::: :::
```sql title="Find by original filename" ```sql title="Find by original filename"
SELECT * FROM "assets" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg'; SELECT * FROM "asset" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg';
SELECT * FROM "assets" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_ SELECT * FROM "asset" 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" LIKE '%_2023_%'; -- all files with _2023_ in the middle
``` ```
```sql title="Find by path" ```sql title="Find by path"
SELECT * FROM "assets" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg'; SELECT * FROM "asset" 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" LIKE 'upload/library/admin/2023/%';
``` ```
### ID
```sql title="Find by 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" ```sql title="Find by partial ID"
SELECT * FROM "assets" WHERE "id"::text LIKE '%ab431d3a%'; SELECT * FROM "asset" WHERE "id"::text LIKE '%ab431d3a%';
``` ```
### Checksum
:::note :::note
You can calculate the checksum for a particular file by using the command `sha1sum <filename>`. You can calculate the checksum for a particular file by using the command `sha1sum <filename>`.
::: :::
```sql title="Find by checksum (SHA-1)" ```sql title="Find by checksum (SHA-1)"
SELECT encode("checksum", 'hex') FROM "assets"; SELECT encode("checksum", 'hex') FROM "asset";
SELECT * FROM "assets" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex'); SELECT * FROM "asset" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex');
SELECT * FROM "assets" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation SELECT * FROM "asset" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation
``` ```
```sql title="Find duplicate assets with identical checksum (SHA-1) (excluding trashed files)" ```sql title="Find duplicate assets with identical checksum (SHA-1) (excluding trashed files)"
SELECT T1."checksum", array_agg(T2."id") ids FROM "assets" T1 SELECT T1."checksum", array_agg(T2."id") ids FROM "asset" T1
INNER JOIN "assets" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL 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"; WHERE T1."deletedAt" IS NULL GROUP BY T1."checksum";
``` ```
### Metadata
```sql title="Live photos" ```sql title="Live photos"
SELECT * FROM "assets" WHERE "livePhotoVideoId" IS NOT NULL; SELECT * FROM "asset" WHERE "livePhotoVideoId" IS NOT NULL;
``` ```
```sql title="By description" ```sql title="By description"
SELECT "assets".*, "exif"."description" FROM "exif" SELECT "asset".*, "asset_exif"."description" FROM "asset_exif"
JOIN "assets" ON "assets"."id" = "exif"."assetId" JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
WHERE TRIM("exif"."description") <> ''; -- all files with a description WHERE TRIM("asset_exif"."description") <> ''; -- all files with a description
SELECT "assets".*, "exif"."description" FROM "exif" SELECT "asset".*, "asset_exif"."description" FROM "asset_exif"
JOIN "assets" ON "assets"."id" = "exif"."assetId" JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
WHERE "exif"."description" ILIKE '%string to match%'; -- search by string WHERE "asset_exif"."description" ILIKE '%string to match%'; -- search by string
``` ```
```sql title="Without metadata" ```sql title="Without metadata"
SELECT "assets".* FROM "exif" SELECT "asset".* FROM "asset_exif"
LEFT JOIN "assets" ON "assets"."id" = "exif"."assetId" LEFT JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
WHERE "exif"."assetId" IS NULL; WHERE "asset_exif"."assetId" IS NULL;
``` ```
```sql title="size < 100,000 bytes, smallest to largest" ```sql title="size < 100,000 bytes, smallest to largest"
SELECT * FROM "assets" SELECT * FROM "asset"
JOIN "exif" ON "assets"."id" = "exif"."assetId" JOIN "asset_exif" ON "asset"."id" = "asset_exif"."assetId"
WHERE "exif"."fileSizeInByte" < 100000 WHERE "asset_exif"."fileSizeInByte" < 100000
ORDER BY "exif"."fileSizeInByte" ASC; ORDER BY "asset_exif"."fileSizeInByte" ASC;
``` ```
```sql title="Without thumbnails" ### Type
SELECT * FROM "assets" WHERE "assets"."previewPath" IS NULL OR "assets"."thumbnailPath" IS NULL;
```
```sql title="By type" ```sql title="By type"
SELECT * FROM "assets" WHERE "assets"."type" = 'VIDEO'; SELECT * FROM "asset" WHERE "asset"."type" = 'VIDEO';
SELECT * FROM "assets" WHERE "assets"."type" = 'IMAGE'; SELECT * FROM "asset" WHERE "asset"."type" = 'IMAGE';
``` ```
```sql title="Count by type" ```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)" ```sql title="Count by type (per user)"
SELECT "users"."email", "assets"."type", COUNT(*) FROM "assets" SELECT "user"."email", "asset"."type", COUNT(*) FROM "asset"
JOIN "users" ON "assets"."ownerId" = "users"."id" JOIN "user" ON "asset"."ownerId" = "user"."id"
GROUP BY "assets"."type", "users"."email" ORDER BY "users"."email"; GROUP BY "asset"."type", "user"."email" ORDER BY "user"."email";
``` ```
```sql title="Failed file movements" ## Tags
SELECT * FROM "move_history";
```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 ## Users
```sql title="List all users" ```sql title="List all users"
SELECT * FROM "users"; SELECT * FROM "user";
``` ```
```sql title="Get owner info from asset ID" ```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 ## Persons
```sql title="Delete person and unset it for the faces it was associated with" ```sql title="Delete person and unset it for the faces it was associated with"
DELETE FROM "person" WHERE "name" = 'PersonNameHere'; 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 ## Postgres internal
```sql title="Change DB_PASSWORD" ```sql title="Change DB_PASSWORD"
+1 -1
View File
@@ -12,7 +12,7 @@ If you want Immich to be able to delete the images in the external library or ad
```diff ```diff
immich-server: immich-server:
volumes: volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload - ${UPLOAD_LOCATION}:/data
+ - /home/user/photos1:/home/user/photos1:ro + - /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 + - /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
``` ```
+18 -21
View File
@@ -29,29 +29,26 @@ These environment variables are used by the `docker-compose.yml` file and do **N
## General ## General
| Variable | Description | Default | Containers | Workers | | Variable | Description | Default | Containers | Workers |
| :---------------------------------- | :---------------------------------------------------------------------------------------- | :---------------------------------: | :----------------------- | :----------------- | | :---------------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- |
| `TZ` | Timezone | <sup>\*1</sup> | server | microservices | | `TZ` | Timezone | <sup>\*1</sup> | server | microservices |
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, 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_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>⚠️ | `/usr/src/app/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 | | `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 | | | `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 | | | `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api | | `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices | | `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices |
| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices | | `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices |
| `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api | | `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api |
| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices | | `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices |
\*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`. \*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`.
`TZ` is used by `exiftool` as a fallback in case the timezone cannot be determined from the image metadata. It is also used for logfile timestamps and cron job execution. `TZ` is used by `exiftool` as a fallback in case the timezone cannot be determined from the image metadata. It is also used for logfile timestamps and cron job execution.
\*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. \*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 ## Workers
| Variable | Description | Default | Containers | | Variable | Description | Default | Containers |
@@ -202,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_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 | | `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 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.
the `_FILE` variable should be set to the path of a file containing the variable value.
| Regular Variable | Equivalent Docker Secrets '\_FILE' Variable | | Regular Variable | Equivalent Docker Secrets '\_FILE' Variable |
| :----------------- | :------------------------------------------ | | :----------------- | :------------------------------------------ |
@@ -229,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-docs]: https://github.com/docker-library/docs/tree/master/postgres#docker-secrets
[docker-secrets]: https://docs.docker.com/engine/swarm/secrets/ [docker-secrets]: https://docs.docker.com/engine/swarm/secrets/
[ioredis]: https://ioredis.readthedocs.io/en/latest/README/#connect-to-redis [ioredis]: https://ioredis.readthedocs.io/en/latest/README/#connect-to-redis
[systemd-creds]: https://systemd.io/CREDENTIALS/
@@ -100,6 +100,11 @@ const projects: CommunityProjectProps[] = [
description: 'Automatically optimize files uploaded to Immich in order to save storage space', description: 'Automatically optimize files uploaded to Immich in order to save storage space',
url: 'https://github.com/miguelangel-nubla/immich-upload-optimizer', 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 { function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {
+20 -1
View File
@@ -2,4 +2,23 @@
## TypeORM Upgrade ## 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.
+4
View File
@@ -1,4 +1,8 @@
[ [
{
"label": "v1.136.0",
"url": "https://v1.136.0.archive.immich.app"
},
{ {
"label": "v1.135.3", "label": "v1.135.3",
"url": "https://v1.135.3.archive.immich.app" "url": "https://v1.135.3.archive.immich.app"
+1 -1
View File
@@ -38,7 +38,7 @@ services:
image: redis:6.2-alpine@sha256:7fe72c486b910f6b1a9769c937dad5d63648ddee82e056f47417542dd40825bb image: redis:6.2-alpine@sha256:7fe72c486b910f6b1a9769c937dad5d63648ddee82e056f47417542dd40825bb
database: 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 command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf
environment: environment:
POSTGRES_PASSWORD: postgres POSTGRES_PASSWORD: postgres
+95 -94
View File
@@ -1,12 +1,12 @@
{ {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.135.3", "version": "1.136.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.135.3", "version": "1.136.0",
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0", "@eslint/eslintrc": "^3.1.0",
@@ -16,14 +16,14 @@
"@playwright/test": "^1.44.1", "@playwright/test": "^1.44.1",
"@socket.io/component-emitter": "^3.1.2", "@socket.io/component-emitter": "^3.1.2",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
"@types/node": "^22.16.4", "@types/node": "^22.16.5",
"@types/oidc-provider": "^9.0.0", "@types/oidc-provider": "^9.0.0",
"@types/pg": "^8.15.1", "@types/pg": "^8.15.1",
"@types/pngjs": "^6.0.4", "@types/pngjs": "^6.0.4",
"@types/supertest": "^6.0.2", "@types/supertest": "^6.0.2",
"@vitest/coverage-v8": "^3.0.0", "@vitest/coverage-v8": "^3.0.0",
"eslint": "^9.14.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-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^59.0.0", "eslint-plugin-unicorn": "^59.0.0",
"exiftool-vendored": "^28.3.1", "exiftool-vendored": "^28.3.1",
@@ -46,7 +46,7 @@
}, },
"../cli": { "../cli": {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.72", "version": "2.2.73",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
@@ -68,13 +68,13 @@
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/micromatch": "^4.0.9", "@types/micromatch": "^4.0.9",
"@types/mock-fs": "^4.13.1", "@types/mock-fs": "^4.13.1",
"@types/node": "^22.16.4", "@types/node": "^22.16.5",
"@vitest/coverage-v8": "^3.0.0", "@vitest/coverage-v8": "^3.0.0",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"cli-progress": "^3.12.0", "cli-progress": "^3.12.0",
"commander": "^12.0.0", "commander": "^12.0.0",
"eslint": "^9.14.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-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^59.0.0", "eslint-plugin-unicorn": "^59.0.0",
"globals": "^16.0.0", "globals": "^16.0.0",
@@ -95,14 +95,14 @@
}, },
"../open-api/typescript-sdk": { "../open-api/typescript-sdk": {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.135.3", "version": "1.136.0",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
"@oazapfts/runtime": "^1.0.2" "@oazapfts/runtime": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.16.4", "@types/node": "^22.16.5",
"typescript": "^5.3.3" "typescript": "^5.3.3"
} }
}, },
@@ -2125,17 +2125,17 @@
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz",
"integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==", "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/type-utils": "8.37.0", "@typescript-eslint/type-utils": "8.38.0",
"@typescript-eslint/utils": "8.37.0", "@typescript-eslint/utils": "8.38.0",
"@typescript-eslint/visitor-keys": "8.37.0", "@typescript-eslint/visitor-keys": "8.38.0",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^7.0.0", "ignore": "^7.0.0",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@@ -2149,7 +2149,7 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.37.0", "@typescript-eslint/parser": "^8.38.0",
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <5.9.0" "typescript": ">=4.8.4 <5.9.0"
} }
@@ -2165,16 +2165,16 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz",
"integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==", "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/typescript-estree": "8.38.0",
"@typescript-eslint/visitor-keys": "8.37.0", "@typescript-eslint/visitor-keys": "8.38.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -2190,14 +2190,14 @@
} }
}, },
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz",
"integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.37.0", "@typescript-eslint/tsconfig-utils": "^8.38.0",
"@typescript-eslint/types": "^8.37.0", "@typescript-eslint/types": "^8.38.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -2212,14 +2212,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz",
"integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/visitor-keys": "8.37.0" "@typescript-eslint/visitor-keys": "8.38.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2230,9 +2230,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz",
"integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2247,15 +2247,15 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz",
"integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==", "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/typescript-estree": "8.38.0",
"@typescript-eslint/utils": "8.37.0", "@typescript-eslint/utils": "8.38.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
@@ -2272,9 +2272,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz",
"integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2286,16 +2286,16 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz",
"integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.37.0", "@typescript-eslint/project-service": "8.38.0",
"@typescript-eslint/tsconfig-utils": "8.37.0", "@typescript-eslint/tsconfig-utils": "8.38.0",
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/visitor-keys": "8.37.0", "@typescript-eslint/visitor-keys": "8.38.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@@ -2341,16 +2341,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz",
"integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.7.0", "@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"@typescript-eslint/typescript-estree": "8.37.0" "@typescript-eslint/typescript-estree": "8.38.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2365,13 +2365,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz",
"integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.37.0", "@typescript-eslint/types": "8.38.0",
"eslint-visitor-keys": "^4.2.1" "eslint-visitor-keys": "^4.2.1"
}, },
"engines": { "engines": {
@@ -3525,9 +3525,9 @@
} }
}, },
"node_modules/eslint-config-prettier": { "node_modules/eslint-config-prettier": {
"version": "10.1.5", "version": "10.1.8",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
"integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -3541,9 +3541,9 @@
} }
}, },
"node_modules/eslint-plugin-prettier": { "node_modules/eslint-plugin-prettier": {
"version": "5.5.1", "version": "5.5.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz",
"integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==", "integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3983,15 +3983,16 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.2", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0", "es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12" "mime-types": "^2.1.12"
}, },
"engines": { "engines": {
@@ -5708,15 +5709,15 @@
} }
}, },
"node_modules/prettier-plugin-organize-imports": { "node_modules/prettier-plugin-organize-imports": {
"version": "4.1.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.2.0.tgz",
"integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", "integrity": "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"prettier": ">=2.0", "prettier": ">=2.0",
"typescript": ">=2.9", "typescript": ">=2.9",
"vue-tsc": "^2.1.0" "vue-tsc": "^2.1.0 || 3"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"vue-tsc": { "vue-tsc": {
@@ -6469,35 +6470,35 @@
} }
}, },
"node_modules/superagent": { "node_modules/superagent": {
"version": "10.2.2", "version": "10.2.3",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.2.tgz", "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz",
"integrity": "sha512-vWMq11OwWCC84pQaFPzF/VO3BrjkCeewuvJgt1jfV0499Z1QSAWN4EqfMM5WlFDDX9/oP8JjlDKpblrmEoyu4Q==", "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"component-emitter": "^1.3.0", "component-emitter": "^1.3.1",
"cookiejar": "^2.1.4", "cookiejar": "^2.1.4",
"debug": "^4.3.4", "debug": "^4.3.7",
"fast-safe-stringify": "^2.1.1", "fast-safe-stringify": "^2.1.1",
"form-data": "^4.0.0", "form-data": "^4.0.4",
"formidable": "^3.5.4", "formidable": "^3.5.4",
"methods": "^1.1.2", "methods": "^1.1.2",
"mime": "2.6.0", "mime": "2.6.0",
"qs": "^6.11.0" "qs": "^6.11.2"
}, },
"engines": { "engines": {
"node": ">=14.18.0" "node": ">=14.18.0"
} }
}, },
"node_modules/supertest": { "node_modules/supertest": {
"version": "7.1.3", "version": "7.1.4",
"resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.3.tgz", "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz",
"integrity": "sha512-ORY0gPa6ojmg/C74P/bDoS21WL6FMXq5I8mawkEz30/zkwdu0gOeqstFy316vHG6OKxqQ+IbGneRemHI8WraEw==", "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"methods": "^1.1.2", "methods": "^1.1.2",
"superagent": "^10.2.2" "superagent": "^10.2.3"
}, },
"engines": { "engines": {
"node": ">=14.18.0" "node": ">=14.18.0"
@@ -6817,16 +6818,16 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.37.0", "version": "8.38.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz",
"integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==", "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.37.0", "@typescript-eslint/eslint-plugin": "8.38.0",
"@typescript-eslint/parser": "8.37.0", "@typescript-eslint/parser": "8.38.0",
"@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/typescript-estree": "8.38.0",
"@typescript-eslint/utils": "8.37.0" "@typescript-eslint/utils": "8.38.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.135.3", "version": "1.136.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"type": "module", "type": "module",
@@ -26,14 +26,14 @@
"@playwright/test": "^1.44.1", "@playwright/test": "^1.44.1",
"@socket.io/component-emitter": "^3.1.2", "@socket.io/component-emitter": "^3.1.2",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
"@types/node": "^22.16.4", "@types/node": "^22.16.5",
"@types/oidc-provider": "^9.0.0", "@types/oidc-provider": "^9.0.0",
"@types/pg": "^8.15.1", "@types/pg": "^8.15.1",
"@types/pngjs": "^6.0.4", "@types/pngjs": "^6.0.4",
"@types/supertest": "^6.0.2", "@types/supertest": "^6.0.2",
"@vitest/coverage-v8": "^3.0.0", "@vitest/coverage-v8": "^3.0.0",
"eslint": "^9.14.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-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^59.0.0", "eslint-plugin-unicorn": "^59.0.0",
"exiftool-vendored": "^28.3.1", "exiftool-vendored": "^28.3.1",
+2 -2
View File
@@ -470,7 +470,7 @@ describe('/albums', () => {
.send({ ids: [asset.id] }); .send({ ids: [asset.id] });
expect(status).toBe(400); 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 () => { it('should add duplicate assets only once', async () => {
@@ -599,7 +599,7 @@ describe('/albums', () => {
.send({ ids: [user1Asset1.id] }); .send({ ids: [user1Asset1.id] });
expect(status).toBe(400); 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 () => { it('should remove duplicate assets only once', async () => {
-12
View File
@@ -186,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) => { unzip: async (input: string, output: string) => {
await execPromise(`unzip -o -d "${output}" "${input}"`); await execPromise(`unzip -o -d "${output}" "${input}"`);
}, },
+1
View File
@@ -37,6 +37,7 @@ test.describe('Registration', () => {
await page.getByRole('button', { name: 'Server Privacy' }).click(); await page.getByRole('button', { name: 'Server Privacy' }).click();
await page.getByRole('button', { name: 'User Privacy' }).click(); await page.getByRole('button', { name: 'User Privacy' }).click();
await page.getByRole('button', { name: 'Storage Template' }).click(); await page.getByRole('button', { name: 'Storage Template' }).click();
await page.getByRole('button', { name: 'Backups' }).click();
await page.getByRole('button', { name: 'Done' }).click(); await page.getByRole('button', { name: 'Done' }).click();
// success // success
+22 -1
View File
@@ -573,6 +573,8 @@
"backup_options_page_title": "Nastavení záloh", "backup_options_page_title": "Nastavení záloh",
"backup_setting_subtitle": "Správa nastavení zálohování na pozadí a na popředí", "backup_setting_subtitle": "Správa nastavení zálohování na pozadí a na popředí",
"backward": "Pozpátku", "backward": "Pozpátku",
"beta_sync": "Stav synchronizace beta verze",
"beta_sync_subtitle": "Správa nového systému synchronizace",
"biometric_auth_enabled": "Biometrické ověřování je povoleno", "biometric_auth_enabled": "Biometrické ověřování je povoleno",
"biometric_locked_out": "Jste vyloučeni z biometrického ověřování", "biometric_locked_out": "Jste vyloučeni z biometrického ověřování",
"biometric_no_options": "Biometrické možnosti nejsou k dispozici", "biometric_no_options": "Biometrické možnosti nejsou k dispozici",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť", "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_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_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_duplicated_assets_title": "Duplicitní položky ({count})",
"cache_settings_statistics_album": "Knihovna náhledů", "cache_settings_statistics_album": "Knihovna náhledů",
"cache_settings_statistics_full": "Kompletní fotografie", "cache_settings_statistics_full": "Kompletní fotografie",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu", "haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu",
"haptic_feedback_title": "Dotyková zpětná vazba", "haptic_feedback_title": "Dotyková zpětná vazba",
"has_quota": "Má kvótu", "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_add_header_tip": "Přidat hlavičku",
"header_settings_field_validator_msg": "Hodnota nemůže být prázdná", "header_settings_field_validator_msg": "Hodnota nemůže být prázdná",
"header_settings_header_name_input": "Název hlavičky", "header_settings_header_name_input": "Název hlavičky",
@@ -1083,6 +1088,7 @@
"host": "Hostitel", "host": "Hostitel",
"hour": "Hodina", "hour": "Hodina",
"id": "ID", "id": "ID",
"idle": "Nečinnost",
"ignore_icloud_photos": "Ignorovat fotografie na iCloudu", "ignore_icloud_photos": "Ignorovat fotografie na iCloudu",
"ignore_icloud_photos_description": "Fotografie uložené na iCloudu se nebudou nahrávat na Immich server", "ignore_icloud_photos_description": "Fotografie uložené na iCloudu se nebudou nahrávat na Immich server",
"image": "Obrázek", "image": "Obrázek",
@@ -1165,7 +1171,9 @@
"list": "Seznam", "list": "Seznam",
"loading": "Načítání", "loading": "Načítání",
"loading_search_results_failed": "Načítání výsledků vyhledávání se nezdařilo", "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_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": "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", "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", "location_permission": "Oprávnění polohy",
@@ -1322,6 +1330,7 @@
"no_results": "Žádné výsledky", "no_results": "Žádné výsledky",
"no_results_description": "Zkuste použít synonymum nebo obecnější klíčové slovo", "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_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_in_any_album": "Bez alba",
"not_selected": "Není vybráno", "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", "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",
@@ -1359,6 +1368,7 @@
"original": "originál", "original": "originál",
"other": "Ostatní", "other": "Ostatní",
"other_devices": "Ostatní zařízení", "other_devices": "Ostatní zařízení",
"other_entities": "Ostatní entity",
"other_variables": "Další proměnné", "other_variables": "Další proměnné",
"owned": "Vlastní", "owned": "Vlastní",
"owner": "Vlastník", "owner": "Vlastník",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Obnovování obličejů", "refreshing_faces": "Obnovování obličejů",
"refreshing_metadata": "Obnovování metadat", "refreshing_metadata": "Obnovování metadat",
"regenerating_thumbnails": "Regenerace miniatur", "regenerating_thumbnails": "Regenerace miniatur",
"remote": "Vzdálený",
"remote_assets": "Vzdálené položky",
"remove": "Odstranit", "remove": "Odstranit",
"remove_assets_album_confirmation": "Opravdu chcete z alba odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?", "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}}?", "remove_assets_shared_link_confirmation": "Opravdu chcete ze sdíleného odkazu odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?",
@@ -1556,11 +1568,15 @@
"reset_password": "Obnovit heslo", "reset_password": "Obnovit heslo",
"reset_people_visibility": "Obnovit viditelnost lidí", "reset_people_visibility": "Obnovit viditelnost lidí",
"reset_pin_code": "Resetovat PIN kód", "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í", "reset_to_default": "Obnovit výchozí nastavení",
"resolve_duplicates": "Vyřešit duplicity", "resolve_duplicates": "Vyřešit duplicity",
"resolved_all_duplicates": "Vyřešeny všechny duplicity", "resolved_all_duplicates": "Vyřešeny všechny duplicity",
"restore": "Obnovit", "restore": "Obnovit",
"restore_all": "Obnovit vše", "restore_all": "Obnovit vše",
"restore_trash_action_prompt": "{count} obnoveno z koše",
"restore_user": "Obnovit uživatele", "restore_user": "Obnovit uživatele",
"restored_asset": "Položka obnovena", "restored_asset": "Položka obnovena",
"resume": "Pokračovat", "resume": "Pokračovat",
@@ -1569,6 +1585,7 @@
"role": "Role", "role": "Role",
"role_editor": "Editor", "role_editor": "Editor",
"role_viewer": "Divák", "role_viewer": "Divák",
"running": "Probíhá",
"save": "Uložit", "save": "Uložit",
"save_to_gallery": "Uložit do galerie", "save_to_gallery": "Uložit do galerie",
"saved_api_key": "API klíč uložen", "saved_api_key": "API klíč uložen",
@@ -1822,6 +1839,7 @@
"storage_quota": "Kvóta úložiště", "storage_quota": "Kvóta úložiště",
"storage_usage": "Využito {used} z {available}", "storage_usage": "Využito {used} z {available}",
"submit": "Odeslat", "submit": "Odeslat",
"success": "Úspěch",
"suggestions": "Návrhy", "suggestions": "Návrhy",
"sunrise_on_the_beach": "Východ slunce na pláži", "sunrise_on_the_beach": "Východ slunce na pláži",
"support": "Podpora", "support": "Podpora",
@@ -1831,6 +1849,8 @@
"sync": "Synchronizovat", "sync": "Synchronizovat",
"sync_albums": "Synchronizovat alba", "sync_albums": "Synchronizovat alba",
"sync_albums_manual_subtitle": "Synchronizovat všechna nahraná videa a fotografie do vybraných záložních alb", "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", "sync_upload_album_setting_subtitle": "Vytvořit a nahrát fotografie a videa do vybraných alb na Immich",
"tag": "Značka", "tag": "Značka",
"tag_assets": "Přiřadit značku", "tag_assets": "Přiřadit značku",
@@ -1841,6 +1861,7 @@
"tag_updated": "Aktualizována značka: {tag}", "tag_updated": "Aktualizována značka: {tag}",
"tagged_assets": "Přiřazena značka {count, plural, one {# položce} other {# položkám}}", "tagged_assets": "Přiřazena značka {count, plural, one {# položce} other {# položkám}}",
"tags": "Značky", "tags": "Značky",
"tap_to_run_job": "Klepnutím na spustíte úlohu",
"template": "Šablona", "template": "Šablona",
"theme": "Motiv", "theme": "Motiv",
"theme_selection": "Výběr motivu", "theme_selection": "Výběr motivu",
+21
View File
@@ -573,6 +573,8 @@
"backup_options_page_title": "Sicherungsoptionen", "backup_options_page_title": "Sicherungsoptionen",
"backup_setting_subtitle": "Verwaltung der Upload-Einstellungen im Hintergrund und im Vordergrund", "backup_setting_subtitle": "Verwaltung der Upload-Einstellungen im Hintergrund und im Vordergrund",
"backward": "Rückwärts", "backward": "Rückwärts",
"beta_sync": "Status des Beta Sync",
"beta_sync_subtitle": "Verwalte das neue Synchronisierungssystem",
"biometric_auth_enabled": "Biometrische Authentifizierung aktiviert", "biometric_auth_enabled": "Biometrische Authentifizierung aktiviert",
"biometric_locked_out": "Du bist von der biometrischen Authentifizierung ausgeschlossen", "biometric_locked_out": "Du bist von der biometrischen Authentifizierung ausgeschlossen",
"biometric_no_options": "Keine biometrischen Optionen verfügbar", "biometric_no_options": "Keine biometrischen Optionen verfügbar",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Haptisches Feedback aktivieren", "haptic_feedback_switch": "Haptisches Feedback aktivieren",
"haptic_feedback_title": "Haptisches Feedback", "haptic_feedback_title": "Haptisches Feedback",
"has_quota": "Kontingent", "has_quota": "Kontingent",
"hash_asset": "Dateihash",
"hashed_assets": "Gehashte Dateien",
"hashing": "Hashen",
"header_settings_add_header_tip": "Header hinzufügen", "header_settings_add_header_tip": "Header hinzufügen",
"header_settings_field_validator_msg": "Der Wert darf nicht leer sein", "header_settings_field_validator_msg": "Der Wert darf nicht leer sein",
"header_settings_header_name_input": "Header-Name", "header_settings_header_name_input": "Header-Name",
@@ -1083,6 +1088,7 @@
"host": "Host", "host": "Host",
"hour": "Stunde", "hour": "Stunde",
"id": "ID", "id": "ID",
"idle": "Untätig",
"ignore_icloud_photos": "iCloud Fotos ignorieren", "ignore_icloud_photos": "iCloud Fotos ignorieren",
"ignore_icloud_photos_description": "Fotos, die in der iCloud gespeichert sind, werden nicht auf den immich Server hochgeladen", "ignore_icloud_photos_description": "Fotos, die in der iCloud gespeichert sind, werden nicht auf den immich Server hochgeladen",
"image": "Bild", "image": "Bild",
@@ -1165,7 +1171,9 @@
"list": "Liste", "list": "Liste",
"loading": "Laden", "loading": "Laden",
"loading_search_results_failed": "Laden von Suchergebnissen fehlgeschlagen", "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_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": "Lokales Netzwerk",
"local_network_sheet_info": "Die App stellt über diese URL eine Verbindung zum Server her, wenn sie das angegebene WLAN-Netzwerk verwendet", "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", "location_permission": "Standort Genehmigung",
@@ -1322,6 +1330,7 @@
"no_results": "Keine Ergebnisse", "no_results": "Keine Ergebnisse",
"no_results_description": "Versuche es mit einem Synonym oder einem allgemeineren Stichwort", "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_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_in_any_album": "In keinem Album",
"not_selected": "Nicht ausgewählt", "not_selected": "Nicht ausgewählt",
"note_apply_storage_label_to_previously_uploaded assets": "Hinweis: Um eine Speicherpfadbezeichnung anzuwenden, starte den", "note_apply_storage_label_to_previously_uploaded assets": "Hinweis: Um eine Speicherpfadbezeichnung anzuwenden, starte den",
@@ -1359,6 +1368,7 @@
"original": "Original", "original": "Original",
"other": "Sonstiges", "other": "Sonstiges",
"other_devices": "Andere Geräte", "other_devices": "Andere Geräte",
"other_entities": "Andere Entitäten",
"other_variables": "Sonstige Variablen", "other_variables": "Sonstige Variablen",
"owned": "Eigenes", "owned": "Eigenes",
"owner": "Besitzer", "owner": "Besitzer",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Gesichter werden aktualisiert", "refreshing_faces": "Gesichter werden aktualisiert",
"refreshing_metadata": "Metadaten werden aktualisiert", "refreshing_metadata": "Metadaten werden aktualisiert",
"regenerating_thumbnails": "Miniaturansichten werden neu erstellt", "regenerating_thumbnails": "Miniaturansichten werden neu erstellt",
"remote": "Entfernt",
"remote_assets": "Entfernte Dateien",
"remove": "Entfernen", "remove": "Entfernen",
"remove_assets_album_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} aus dem Album entfernen willst?", "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?", "remove_assets_shared_link_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} von diesem geteilten Link entfernen willst?",
@@ -1556,11 +1568,15 @@
"reset_password": "Passwort zurücksetzen", "reset_password": "Passwort zurücksetzen",
"reset_people_visibility": "Sichtbarkeit von Personen zurücksetzen", "reset_people_visibility": "Sichtbarkeit von Personen zurücksetzen",
"reset_pin_code": "PIN Code 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", "reset_to_default": "Auf Standard zurücksetzen",
"resolve_duplicates": "Duplikate entfernen", "resolve_duplicates": "Duplikate entfernen",
"resolved_all_duplicates": "Alle Duplikate aufgelöst", "resolved_all_duplicates": "Alle Duplikate aufgelöst",
"restore": "Wiederherstellen", "restore": "Wiederherstellen",
"restore_all": "Alle wiederherstellen", "restore_all": "Alle wiederherstellen",
"restore_trash_action_prompt": "{count} aus dem Papierkorb wiederhergestellt",
"restore_user": "Nutzer wiederherstellen", "restore_user": "Nutzer wiederherstellen",
"restored_asset": "Datei wiederhergestellt", "restored_asset": "Datei wiederhergestellt",
"resume": "Fortsetzen", "resume": "Fortsetzen",
@@ -1569,6 +1585,7 @@
"role": "Rolle", "role": "Rolle",
"role_editor": "Bearbeiter", "role_editor": "Bearbeiter",
"role_viewer": "Betrachter", "role_viewer": "Betrachter",
"running": "Läuft",
"save": "Speichern", "save": "Speichern",
"save_to_gallery": "In Galerie speichern", "save_to_gallery": "In Galerie speichern",
"saved_api_key": "API-Schlüssel wurde gespeichert", "saved_api_key": "API-Schlüssel wurde gespeichert",
@@ -1822,6 +1839,7 @@
"storage_quota": "Speicherplatz-Kontingent", "storage_quota": "Speicherplatz-Kontingent",
"storage_usage": "{used} von {available} verwendet", "storage_usage": "{used} von {available} verwendet",
"submit": "Bestätigen", "submit": "Bestätigen",
"success": "Erfolgreich",
"suggestions": "Vorschläge", "suggestions": "Vorschläge",
"sunrise_on_the_beach": "Sonnenaufgang am Strand", "sunrise_on_the_beach": "Sonnenaufgang am Strand",
"support": "Unterstützung", "support": "Unterstützung",
@@ -1831,6 +1849,8 @@
"sync": "Synchronisieren", "sync": "Synchronisieren",
"sync_albums": "Alben synchronisieren", "sync_albums": "Alben synchronisieren",
"sync_albums_manual_subtitle": "Synchronisiere alle hochgeladenen Videos und Fotos in die ausgewählten Backup-Alben", "sync_albums_manual_subtitle": "Synchronisiere alle hochgeladenen Videos und Fotos in die ausgewählten Backup-Alben",
"sync_local": "Lokal synchronisieren",
"sync_remote": "Entfernt synchronisieren",
"sync_upload_album_setting_subtitle": "Erstelle deine ausgewählten Alben in Immich und lade die Fotos und Videos dort hoch", "sync_upload_album_setting_subtitle": "Erstelle deine ausgewählten Alben in Immich und lade die Fotos und Videos dort hoch",
"tag": "Tag", "tag": "Tag",
"tag_assets": "Dateien taggen", "tag_assets": "Dateien taggen",
@@ -1841,6 +1861,7 @@
"tag_updated": "Tag aktualisiert: {tag}", "tag_updated": "Tag aktualisiert: {tag}",
"tagged_assets": "{count, plural, one {# Datei} other {# Dateien}} getagged", "tagged_assets": "{count, plural, one {# Datei} other {# Dateien}} getagged",
"tags": "Tags", "tags": "Tags",
"tap_to_run_job": "Tippen um den Job zu starten",
"template": "Vorlage", "template": "Vorlage",
"theme": "Theme", "theme": "Theme",
"theme_selection": "Themenauswahl", "theme_selection": "Themenauswahl",
+27 -4
View File
@@ -14,6 +14,7 @@
"add_a_location": "Add a location", "add_a_location": "Add a location",
"add_a_name": "Add a name", "add_a_name": "Add a name",
"add_a_title": "Add a title", "add_a_title": "Add a title",
"add_birthday": "Add a birthday",
"add_endpoint": "Add endpoint", "add_endpoint": "Add endpoint",
"add_exclusion_pattern": "Add exclusion pattern", "add_exclusion_pattern": "Add exclusion pattern",
"add_import_path": "Add import path", "add_import_path": "Add import path",
@@ -44,6 +45,13 @@
"backup_database": "Create Database Dump", "backup_database": "Create Database Dump",
"backup_database_enable_description": "Enable database dumps", "backup_database_enable_description": "Enable database dumps",
"backup_keep_last_amount": "Amount of previous dumps to keep", "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": "Database Dump Settings",
"backup_settings_description": "Manage database dump settings.", "backup_settings_description": "Manage database dump settings.",
"cleared_jobs": "Cleared jobs for: {job}", "cleared_jobs": "Cleared jobs for: {job}",
@@ -397,6 +405,7 @@
"album_cover_updated": "Album cover updated", "album_cover_updated": "Album cover updated",
"album_delete_confirmation": "Are you sure you want to delete the album {album}?", "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_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_excluded": "EXCLUDED",
"album_info_card_backup_album_included": "INCLUDED", "album_info_card_backup_album_included": "INCLUDED",
"album_info_updated": "Album info updated", "album_info_updated": "Album info updated",
@@ -510,6 +519,7 @@
"back_close_deselect": "Back, close, or deselect", "back_close_deselect": "Back, close, or deselect",
"background_location_permission": "Background location permission", "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", "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_device": "Albums on device ({count})",
"backup_album_selection_page_albums_tap": "Tap to include, double tap to exclude", "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.", "backup_album_selection_page_assets_scatter": "Assets can scatter across multiple albums. Thus, albums can be included or excluded during the backup process.",
@@ -723,6 +733,7 @@
"current_server_address": "Current server address", "current_server_address": "Current server address",
"custom_locale": "Custom Locale", "custom_locale": "Custom Locale",
"custom_locale_description": "Format dates and numbers based on the language and the region", "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": "E, MMM dd",
"daily_title_text_date_year": "E, MMM dd, yyyy", "daily_title_text_date_year": "E, MMM dd, yyyy",
"dark": "Dark", "dark": "Dark",
@@ -742,7 +753,8 @@
"default_locale": "Default Locale", "default_locale": "Default Locale",
"default_locale_description": "Format dates and numbers based on your browser locale", "default_locale_description": "Format dates and numbers based on your browser locale",
"delete": "Delete", "delete": "Delete",
"delete_action_prompt": "{count} deleted permanently", "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_album": "Delete album",
"delete_api_key_prompt": "Are you sure you want to delete this API key?", "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", "delete_dialog_alert": "These items will be permanently deleted from Immich and from your device",
@@ -760,6 +772,8 @@
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only", "delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
"delete_local_dialog_ok_force": "Delete Anyway", "delete_local_dialog_ok_force": "Delete Anyway",
"delete_others": "Delete others", "delete_others": "Delete others",
"delete_permanently": "Delete permanently",
"delete_permanently_action_prompt": "{count} deleted permanently",
"delete_shared_link": "Delete shared link", "delete_shared_link": "Delete shared link",
"delete_shared_link_dialog_title": "Delete Shared Link", "delete_shared_link_dialog_title": "Delete Shared Link",
"delete_tag": "Delete tag", "delete_tag": "Delete tag",
@@ -815,6 +829,7 @@
"edit": "Edit", "edit": "Edit",
"edit_album": "Edit album", "edit_album": "Edit album",
"edit_avatar": "Edit avatar", "edit_avatar": "Edit avatar",
"edit_birthday": "Edit Birthday",
"edit_date": "Edit date", "edit_date": "Edit date",
"edit_date_and_time": "Edit date and time", "edit_date_and_time": "Edit date and time",
"edit_description": "Edit description", "edit_description": "Edit description",
@@ -982,6 +997,7 @@
}, },
"exif": "Exif", "exif": "Exif",
"exif_bottom_sheet_description": "Add Description...", "exif_bottom_sheet_description": "Add Description...",
"exif_bottom_sheet_description_error": "Error updating description",
"exif_bottom_sheet_details": "DETAILS", "exif_bottom_sheet_details": "DETAILS",
"exif_bottom_sheet_location": "LOCATION", "exif_bottom_sheet_location": "LOCATION",
"exif_bottom_sheet_people": "PEOPLE", "exif_bottom_sheet_people": "PEOPLE",
@@ -1002,6 +1018,8 @@
"explorer": "Explorer", "explorer": "Explorer",
"export": "Export", "export": "Export",
"export_as_json": "Export as JSON", "export_as_json": "Export as JSON",
"export_database": "Export Database",
"export_database_description": "Export the SQLite database",
"extension": "Extension", "extension": "Extension",
"external": "External", "external": "External",
"external_libraries": "External Libraries", "external_libraries": "External Libraries",
@@ -1146,6 +1164,7 @@
"language_no_results_title": "No languages found", "language_no_results_title": "No languages found",
"language_search_hint": "Search languages...", "language_search_hint": "Search languages...",
"language_setting_description": "Select your preferred language", "language_setting_description": "Select your preferred language",
"large_files": "Large Files",
"last_seen": "Last seen", "last_seen": "Last seen",
"latest_version": "Latest Version", "latest_version": "Latest Version",
"latitude": "Latitude", "latitude": "Latitude",
@@ -1165,7 +1184,6 @@
"light": "Light", "light": "Light",
"like_deleted": "Like deleted", "like_deleted": "Like deleted",
"link_motion_video": "Link motion video", "link_motion_video": "Link motion video",
"link_options": "Link options",
"link_to_oauth": "Link to OAuth", "link_to_oauth": "Link to OAuth",
"linked_oauth_account": "Linked OAuth account", "linked_oauth_account": "Linked OAuth account",
"list": "List", "list": "List",
@@ -1230,8 +1248,7 @@
"manage_your_devices": "Manage your logged-in devices", "manage_your_devices": "Manage your logged-in devices",
"manage_your_oauth_connection": "Manage your OAuth connection", "manage_your_oauth_connection": "Manage your OAuth connection",
"map": "Map", "map": "Map",
"map_assets_in_bound": "{count} photo", "map_assets_in_bounds": "{count, plural, one {# photo} other {# photos}}",
"map_assets_in_bounds": "{count} photos",
"map_cannot_get_user_location": "Cannot get user's location", "map_cannot_get_user_location": "Cannot get user's location",
"map_location_dialog_yes": "Yes", "map_location_dialog_yes": "Yes",
"map_location_picker_page_use_location": "Use this location", "map_location_picker_page_use_location": "Use this location",
@@ -1582,6 +1599,7 @@
"resume": "Resume", "resume": "Resume",
"retry_upload": "Retry upload", "retry_upload": "Retry upload",
"review_duplicates": "Review duplicates", "review_duplicates": "Review duplicates",
"review_large_files": "Review large files",
"role": "Role", "role": "Role",
"role_editor": "Editor", "role_editor": "Editor",
"role_viewer": "Viewer", "role_viewer": "Viewer",
@@ -1739,6 +1757,7 @@
"shared_link_clipboard_copied_massage": "Copied to clipboard", "shared_link_clipboard_copied_massage": "Copied to clipboard",
"shared_link_clipboard_text": "Link: {link}\nPassword: {password}", "shared_link_clipboard_text": "Link: {link}\nPassword: {password}",
"shared_link_create_error": "Error while creating shared link", "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_description_hint": "Enter the share description",
"shared_link_edit_expire_after_option_day": "1 day", "shared_link_edit_expire_after_option_day": "1 day",
"shared_link_edit_expire_after_option_days": "{count} days", "shared_link_edit_expire_after_option_days": "{count} days",
@@ -1764,6 +1783,7 @@
"shared_link_info_chip_metadata": "EXIF", "shared_link_info_chip_metadata": "EXIF",
"shared_link_manage_links": "Manage Shared links", "shared_link_manage_links": "Manage Shared links",
"shared_link_options": "Shared link options", "shared_link_options": "Shared link options",
"shared_link_password_description": "Require a password to access this shared link",
"shared_links": "Shared links", "shared_links": "Shared links",
"shared_links_description": "Share photos and videos with a link", "shared_links_description": "Share photos and videos with a link",
"shared_photos_and_videos_count": "{assetCount, plural, other {# shared photos & videos.}}", "shared_photos_and_videos_count": "{assetCount, plural, other {# shared photos & videos.}}",
@@ -1941,11 +1961,13 @@
"updated_at": "Updated", "updated_at": "Updated",
"updated_password": "Updated password", "updated_password": "Updated password",
"upload": "Upload", "upload": "Upload",
"upload_action_prompt": "{count} queued for upload",
"upload_concurrency": "Upload concurrency", "upload_concurrency": "Upload concurrency",
"upload_details": "Upload Details", "upload_details": "Upload Details",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?", "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_title": "Upload Asset", "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_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_progress": "Remaining {remaining, number} - Processed {processed, number}/{total, number}",
"upload_skipped_duplicates": "Skipped {count, plural, one {# duplicate asset} other {# duplicate assets}}", "upload_skipped_duplicates": "Skipped {count, plural, one {# duplicate asset} other {# duplicate assets}}",
"upload_status_duplicates": "Duplicates", "upload_status_duplicates": "Duplicates",
@@ -1954,6 +1976,7 @@
"upload_success": "Upload success, refresh the page to see new upload assets.", "upload_success": "Upload success, refresh the page to see new upload assets.",
"upload_to_immich": "Upload to Immich ({count})", "upload_to_immich": "Upload to Immich ({count})",
"uploading": "Uploading", "uploading": "Uploading",
"uploading_media": "Uploading media",
"url": "URL", "url": "URL",
"usage": "Usage", "usage": "Usage",
"use_biometric": "Use biometric", "use_biometric": "Use biometric",
+22 -1
View File
@@ -573,6 +573,8 @@
"backup_options_page_title": "Varundamise valikud", "backup_options_page_title": "Varundamise valikud",
"backup_setting_subtitle": "Halda taustal ja esiplaanil üleslaadimise seadeid", "backup_setting_subtitle": "Halda taustal ja esiplaanil üleslaadimise seadeid",
"backward": "Tagasi", "backward": "Tagasi",
"beta_sync": "Beeta sünkroonimise staatus",
"beta_sync_subtitle": "Halda uut sünkroonimissüsteemi",
"biometric_auth_enabled": "Biomeetriline autentimine lubatud", "biometric_auth_enabled": "Biomeetriline autentimine lubatud",
"biometric_locked_out": "Biomeetriline autentimine on blokeeritud", "biometric_locked_out": "Biomeetriline autentimine on blokeeritud",
"biometric_no_options": "Biomeetrilisi valikuid ei ole", "biometric_no_options": "Biomeetrilisi valikuid ei ole",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Tühjenda puhver", "cache_settings_clear_cache_button": "Tühjenda puhver",
"cache_settings_clear_cache_button_title": "Tühjendab rakenduse puhvri. See mõjutab oluliselt rakenduse jõudlust, kuni puhver uuesti täidetakse.", "cache_settings_clear_cache_button_title": "Tühjendab rakenduse puhvri. See mõjutab oluliselt rakenduse jõudlust, kuni puhver uuesti täidetakse.",
"cache_settings_duplicated_assets_clear_button": "TÜHJENDA", "cache_settings_duplicated_assets_clear_button": "TÜHJENDA",
"cache_settings_duplicated_assets_subtitle": "Fotod ja videod, mis on rakenduse poolt mustfiltreeritud", "cache_settings_duplicated_assets_subtitle": "Fotod ja videod, mis on rakenduse poolt ignoreeritud",
"cache_settings_duplicated_assets_title": "Dubleeritud üksused ({count})", "cache_settings_duplicated_assets_title": "Dubleeritud üksused ({count})",
"cache_settings_statistics_album": "Kogu pisipildid", "cache_settings_statistics_album": "Kogu pisipildid",
"cache_settings_statistics_full": "Täismõõdus pildid", "cache_settings_statistics_full": "Täismõõdus pildid",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Luba haptiline tagasiside", "haptic_feedback_switch": "Luba haptiline tagasiside",
"haptic_feedback_title": "Haptiline tagasiside", "haptic_feedback_title": "Haptiline tagasiside",
"has_quota": "On kvoot", "has_quota": "On kvoot",
"hash_asset": "Arvuta üksuse räsi",
"hashed_assets": "Räsiga üksused",
"hashing": "Räsi arvutamine",
"header_settings_add_header_tip": "Lisa päis", "header_settings_add_header_tip": "Lisa päis",
"header_settings_field_validator_msg": "Väärtus ei saa olla tühi", "header_settings_field_validator_msg": "Väärtus ei saa olla tühi",
"header_settings_header_name_input": "Päise nimi", "header_settings_header_name_input": "Päise nimi",
@@ -1083,6 +1088,7 @@
"host": "Host", "host": "Host",
"hour": "Tund", "hour": "Tund",
"id": "ID", "id": "ID",
"idle": "Jõude",
"ignore_icloud_photos": "Ignoreeri iCloud fotosid", "ignore_icloud_photos": "Ignoreeri iCloud fotosid",
"ignore_icloud_photos_description": "Fotosid, mis on iCloud'is, ei laadita üles Immich'i serverisse", "ignore_icloud_photos_description": "Fotosid, mis on iCloud'is, ei laadita üles Immich'i serverisse",
"image": "Pilt", "image": "Pilt",
@@ -1165,7 +1171,9 @@
"list": "Loend", "list": "Loend",
"loading": "Laadimine", "loading": "Laadimine",
"loading_search_results_failed": "Otsitulemuste laadimine ebaõnnestus", "loading_search_results_failed": "Otsitulemuste laadimine ebaõnnestus",
"local": "Lokaalne üksus",
"local_asset_cast_failed": "Ei saa edastada üksust, mis pole serverisse üles laaditud", "local_asset_cast_failed": "Ei saa edastada üksust, mis pole serverisse üles laaditud",
"local_assets": "Lokaalsed üksused",
"local_network": "Kohalik võrk", "local_network": "Kohalik võrk",
"local_network_sheet_info": "Rakendus ühendub valitud Wi-Fi võrgus olles serveriga selle URL-i kaudu", "local_network_sheet_info": "Rakendus ühendub valitud Wi-Fi võrgus olles serveriga selle URL-i kaudu",
"location_permission": "Asukoha luba", "location_permission": "Asukoha luba",
@@ -1322,6 +1330,7 @@
"no_results": "Vasteid pole", "no_results": "Vasteid pole",
"no_results_description": "Proovi sünonüümi või üldisemat märksõna", "no_results_description": "Proovi sünonüümi või üldisemat märksõna",
"no_shared_albums_message": "Lisa album, et fotosid ja videosid teistega jagada", "no_shared_albums_message": "Lisa album, et fotosid ja videosid teistega jagada",
"no_uploads_in_progress": "Üleslaadimisi käimas ei ole",
"not_in_any_album": "Pole üheski albumis", "not_in_any_album": "Pole üheski albumis",
"not_selected": "Ei ole valitud", "not_selected": "Ei ole valitud",
"note_apply_storage_label_to_previously_uploaded assets": "Märkus: Et rakendada talletussilt varem üleslaaditud üksustele, käivita", "note_apply_storage_label_to_previously_uploaded assets": "Märkus: Et rakendada talletussilt varem üleslaaditud üksustele, käivita",
@@ -1359,6 +1368,7 @@
"original": "originaal", "original": "originaal",
"other": "Muud", "other": "Muud",
"other_devices": "Muud seadmed", "other_devices": "Muud seadmed",
"other_entities": "Muud objektid",
"other_variables": "Muud muutujad", "other_variables": "Muud muutujad",
"owned": "Minu omad", "owned": "Minu omad",
"owner": "Omanik", "owner": "Omanik",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Nägude värskendamine", "refreshing_faces": "Nägude värskendamine",
"refreshing_metadata": "Metaandmete värskendamine", "refreshing_metadata": "Metaandmete värskendamine",
"regenerating_thumbnails": "Pisipiltide uuesti genereerimine", "regenerating_thumbnails": "Pisipiltide uuesti genereerimine",
"remote": "Kaugüksus",
"remote_assets": "Kaugüksused",
"remove": "Eemalda", "remove": "Eemalda",
"remove_assets_album_confirmation": "Kas oled kindel, et soovid {count, plural, one {# üksuse} other {# üksust}} albumist eemaldada?", "remove_assets_album_confirmation": "Kas oled kindel, et soovid {count, plural, one {# üksuse} other {# üksust}} albumist eemaldada?",
"remove_assets_shared_link_confirmation": "Kas oled kindel, et soovid eemaldada {count, plural, one {# üksuse} other {# üksust}} sellelt jagatud lingilt?", "remove_assets_shared_link_confirmation": "Kas oled kindel, et soovid eemaldada {count, plural, one {# üksuse} other {# üksust}} sellelt jagatud lingilt?",
@@ -1556,11 +1568,15 @@
"reset_password": "Lähtesta parool", "reset_password": "Lähtesta parool",
"reset_people_visibility": "Lähtesta isikute nähtavus", "reset_people_visibility": "Lähtesta isikute nähtavus",
"reset_pin_code": "Lähtesta PIN-kood", "reset_pin_code": "Lähtesta PIN-kood",
"reset_sqlite": "Lähtesta SQLite andmebaas",
"reset_sqlite_confirmation": "Kas oled kindel, et soovid SQLite andmebaasi lähtestada? Andmete uuesti sünkroonimiseks pead välja ja jälle sisse logima",
"reset_sqlite_success": "SQLite andmebaas edukalt lähtestatud",
"reset_to_default": "Lähtesta", "reset_to_default": "Lähtesta",
"resolve_duplicates": "Lahenda duplikaadid", "resolve_duplicates": "Lahenda duplikaadid",
"resolved_all_duplicates": "Kõik duplikaadid lahendatud", "resolved_all_duplicates": "Kõik duplikaadid lahendatud",
"restore": "Taasta", "restore": "Taasta",
"restore_all": "Taasta kõik", "restore_all": "Taasta kõik",
"restore_trash_action_prompt": "{count} prügikastust taastatud",
"restore_user": "Taasta kasutaja", "restore_user": "Taasta kasutaja",
"restored_asset": "Üksus taastatud", "restored_asset": "Üksus taastatud",
"resume": "Jätka", "resume": "Jätka",
@@ -1569,6 +1585,7 @@
"role": "Roll", "role": "Roll",
"role_editor": "Muutja", "role_editor": "Muutja",
"role_viewer": "Vaataja", "role_viewer": "Vaataja",
"running": "Käimas",
"save": "Salvesta", "save": "Salvesta",
"save_to_gallery": "Salvesta galeriisse", "save_to_gallery": "Salvesta galeriisse",
"saved_api_key": "API võti salvestatud", "saved_api_key": "API võti salvestatud",
@@ -1822,6 +1839,7 @@
"storage_quota": "Talletuskvoot", "storage_quota": "Talletuskvoot",
"storage_usage": "{used}/{available} kasutatud", "storage_usage": "{used}/{available} kasutatud",
"submit": "Saada", "submit": "Saada",
"success": "Õnnestus",
"suggestions": "Soovitused", "suggestions": "Soovitused",
"sunrise_on_the_beach": "Päikesetõus rannal", "sunrise_on_the_beach": "Päikesetõus rannal",
"support": "Tugi", "support": "Tugi",
@@ -1831,6 +1849,8 @@
"sync": "Sünkrooni", "sync": "Sünkrooni",
"sync_albums": "Sünkrooni albumid", "sync_albums": "Sünkrooni albumid",
"sync_albums_manual_subtitle": "Sünkrooni kõik üleslaaditud videod ja fotod valitud varundusalbumitesse", "sync_albums_manual_subtitle": "Sünkrooni kõik üleslaaditud videod ja fotod valitud varundusalbumitesse",
"sync_local": "Sünkrooni lokaalsed üksused",
"sync_remote": "Sünkrooni kaugüksused",
"sync_upload_album_setting_subtitle": "Loo ja laadi oma pildid ja videod üles Immich'isse valitud albumitesse", "sync_upload_album_setting_subtitle": "Loo ja laadi oma pildid ja videod üles Immich'isse valitud albumitesse",
"tag": "Silt", "tag": "Silt",
"tag_assets": "Sildista üksuseid", "tag_assets": "Sildista üksuseid",
@@ -1841,6 +1861,7 @@
"tag_updated": "Muudetud silt: {tag}", "tag_updated": "Muudetud silt: {tag}",
"tagged_assets": "{count, plural, one {# üksus} other {# üksust}} sildistatud", "tagged_assets": "{count, plural, one {# üksus} other {# üksust}} sildistatud",
"tags": "Sildid", "tags": "Sildid",
"tap_to_run_job": "Puuduta tööte käivitamiseks",
"template": "Mall", "template": "Mall",
"theme": "Teema", "theme": "Teema",
"theme_selection": "Teema valik", "theme_selection": "Teema valik",
+28
View File
@@ -406,6 +406,7 @@
"album_options": "Options de l'album", "album_options": "Options de l'album",
"album_remove_user": "Supprimer l'utilisateur?", "album_remove_user": "Supprimer l'utilisateur?",
"album_remove_user_confirmation": "Êtes-vous sûr de vouloir supprimer {user}?", "album_remove_user_confirmation": "Êtes-vous sûr de vouloir supprimer {user}?",
"album_search_not_found": "Aucun album trouvé ne correspond à votre recherche",
"album_share_no_users": "Il semble que vous ayez partagé cet album avec tous les utilisateurs ou que vous n'ayez aucun utilisateur avec lequel le partager.", "album_share_no_users": "Il semble que vous ayez partagé cet album avec tous les utilisateurs ou que vous n'ayez aucun utilisateur avec lequel le partager.",
"album_updated": "Album mis à jour", "album_updated": "Album mis à jour",
"album_updated_setting_description": "Recevoir une notification par courriel lorsqu'un album partagé a de nouveaux médias", "album_updated_setting_description": "Recevoir une notification par courriel lorsqu'un album partagé a de nouveaux médias",
@@ -425,6 +426,7 @@
"albums_default_sort_order": "Ordre de tri par défaut des albums", "albums_default_sort_order": "Ordre de tri par défaut des albums",
"albums_default_sort_order_description": "Ordre de tri des médias pour les nouveaux albums créés.", "albums_default_sort_order_description": "Ordre de tri des médias pour les nouveaux albums créés.",
"albums_feature_description": "Bibliothèques de médias pouvant être partagés avec d'autres utilisateurs.", "albums_feature_description": "Bibliothèques de médias pouvant être partagés avec d'autres utilisateurs.",
"albums_on_device_count": "Album sur l'appareil ({count})",
"all": "Tout", "all": "Tout",
"all_albums": "Tous les albums", "all_albums": "Tous les albums",
"all_people": "Toutes les personnes", "all_people": "Toutes les personnes",
@@ -571,6 +573,8 @@
"backup_options_page_title": "Options de sauvegarde", "backup_options_page_title": "Options de sauvegarde",
"backup_setting_subtitle": "Ajuster les paramètres d'envoi au premier et en arrière-plan", "backup_setting_subtitle": "Ajuster les paramètres d'envoi au premier et en arrière-plan",
"backward": "Arrière", "backward": "Arrière",
"beta_sync": "Statut de la synchronisation béta",
"beta_sync_subtitle": "Gérer le nouveau système de synchronisation",
"biometric_auth_enabled": "Authentification biométrique activée", "biometric_auth_enabled": "Authentification biométrique activée",
"biometric_locked_out": "L'authentification biométrique est verrouillé", "biometric_locked_out": "L'authentification biométrique est verrouillé",
"biometric_no_options": "Aucune option biométrique disponible", "biometric_no_options": "Aucune option biométrique disponible",
@@ -605,6 +609,7 @@
"cancel": "Annuler", "cancel": "Annuler",
"cancel_search": "Annuler la recherche", "cancel_search": "Annuler la recherche",
"canceled": "Annulé", "canceled": "Annulé",
"canceling": "Annulation",
"cannot_merge_people": "Impossible de fusionner les personnes", "cannot_merge_people": "Impossible de fusionner les personnes",
"cannot_undo_this_action": "Vous ne pouvez pas annuler cette action!", "cannot_undo_this_action": "Vous ne pouvez pas annuler cette action!",
"cannot_update_the_description": "Impossible de mettre à jour la description", "cannot_update_the_description": "Impossible de mettre à jour la description",
@@ -765,6 +770,7 @@
"description": "Description", "description": "Description",
"description_input_hint_text": "Ajouter une description...", "description_input_hint_text": "Ajouter une description...",
"description_input_submit_error": "Erreur de mise à jour de la description, vérifier le journal pour plus de détails", "description_input_submit_error": "Erreur de mise à jour de la description, vérifier le journal pour plus de détails",
"deselect_all": "Tout désélectionner",
"details": "Détails", "details": "Détails",
"direction": "Ordre", "direction": "Ordre",
"disabled": "Désactivé", "disabled": "Désactivé",
@@ -839,6 +845,7 @@
"empty_trash": "Vider la corbeille", "empty_trash": "Vider la corbeille",
"empty_trash_confirmation": "Êtes-vous sûr de vouloir vider la corbeille? Cela supprimera définitivement de Immich tous les médias qu'elle contient.\nVous ne pouvez pas annuler cette action!", "empty_trash_confirmation": "Êtes-vous sûr de vouloir vider la corbeille? Cela supprimera définitivement de Immich tous les médias qu'elle contient.\nVous ne pouvez pas annuler cette action!",
"enable": "Active", "enable": "Active",
"enable_backup": "Activer Backup",
"enable_biometric_auth_description": "Entrez votre code PIN pour activer l'authentification biométrique", "enable_biometric_auth_description": "Entrez votre code PIN pour activer l'authentification biométrique",
"enabled": "Activé", "enabled": "Activé",
"end_date": "Date de fin", "end_date": "Date de fin",
@@ -1046,6 +1053,9 @@
"haptic_feedback_switch": "Activer le retour haptique", "haptic_feedback_switch": "Activer le retour haptique",
"haptic_feedback_title": "Retour haptique", "haptic_feedback_title": "Retour haptique",
"has_quota": "Quota", "has_quota": "Quota",
"hash_asset": "Hasher le média",
"hashed_assets": "Média hashés",
"hashing": "Hash",
"header_settings_add_header_tip": "Ajouter un en-tête", "header_settings_add_header_tip": "Ajouter un en-tête",
"header_settings_field_validator_msg": "Cette valeur ne peut pas être vide", "header_settings_field_validator_msg": "Cette valeur ne peut pas être vide",
"header_settings_header_name_input": "Nom de l'en-tête", "header_settings_header_name_input": "Nom de l'en-tête",
@@ -1160,7 +1170,9 @@
"list": "Liste", "list": "Liste",
"loading": "Chargement", "loading": "Chargement",
"loading_search_results_failed": "Chargement des résultats échoué", "loading_search_results_failed": "Chargement des résultats échoué",
"local": "Local",
"local_asset_cast_failed": "Impossible de caster un média qui n'a pas envoyé vers le serveur", "local_asset_cast_failed": "Impossible de caster un média qui n'a pas envoyé vers le serveur",
"local_assets": "Média locaux",
"local_network": "Réseau local", "local_network": "Réseau local",
"local_network_sheet_info": "L'application va se connecter au serveur via cette URL quand l'appareil est connecté à ce réseau Wi-Fi", "local_network_sheet_info": "L'application va se connecter au serveur via cette URL quand l'appareil est connecté à ce réseau Wi-Fi",
"location_permission": "Autorisation de localisation", "location_permission": "Autorisation de localisation",
@@ -1317,6 +1329,7 @@
"no_results": "Aucun résultat", "no_results": "Aucun résultat",
"no_results_description": "Essayez un synonyme ou un mot-clé plus général", "no_results_description": "Essayez un synonyme ou un mot-clé plus général",
"no_shared_albums_message": "Créer un album pour partager vos photos et vidéos avec les personnes de votre réseau", "no_shared_albums_message": "Créer un album pour partager vos photos et vidéos avec les personnes de votre réseau",
"no_uploads_in_progress": "Pas d'envoi en cours",
"not_in_any_album": "Dans aucun album", "not_in_any_album": "Dans aucun album",
"not_selected": "Non sélectionné", "not_selected": "Non sélectionné",
"note_apply_storage_label_to_previously_uploaded assets": "Note : Pour appliquer l'étiquette de stockage aux médias précédemment envoyés, exécutez", "note_apply_storage_label_to_previously_uploaded assets": "Note : Pour appliquer l'étiquette de stockage aux médias précédemment envoyés, exécutez",
@@ -1354,6 +1367,7 @@
"original": "original", "original": "original",
"other": "Autre", "other": "Autre",
"other_devices": "Autres appareils", "other_devices": "Autres appareils",
"other_entities": "Autres entités",
"other_variables": "Autres variables", "other_variables": "Autres variables",
"owned": "Possédé", "owned": "Possédé",
"owner": "Propriétaire", "owner": "Propriétaire",
@@ -1485,6 +1499,7 @@
"purchase_server_description_2": "Statut de contributeur", "purchase_server_description_2": "Statut de contributeur",
"purchase_server_title": "Serveur", "purchase_server_title": "Serveur",
"purchase_settings_server_activated": "La clé du produit pour le Serveur est gérée par l'administrateur", "purchase_settings_server_activated": "La clé du produit pour le Serveur est gérée par l'administrateur",
"queue_status": "File d'attente {count}/{total}",
"rating": "Étoile d'évaluation", "rating": "Étoile d'évaluation",
"rating_clear": "Effacer l'évaluation", "rating_clear": "Effacer l'évaluation",
"rating_count": "{count, plural, one {# étoile} other {# étoiles}}", "rating_count": "{count, plural, one {# étoile} other {# étoiles}}",
@@ -1513,6 +1528,8 @@
"refreshing_faces": "Actualisation des visages", "refreshing_faces": "Actualisation des visages",
"refreshing_metadata": "Actualisation des métadonnées", "refreshing_metadata": "Actualisation des métadonnées",
"regenerating_thumbnails": "Regénération des miniatures", "regenerating_thumbnails": "Regénération des miniatures",
"remote": "A distance",
"remote_assets": "Média à distance",
"remove": "Supprimer", "remove": "Supprimer",
"remove_assets_album_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de l'album?", "remove_assets_album_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de l'album?",
"remove_assets_shared_link_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de ce lien partagé ?", "remove_assets_shared_link_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de ce lien partagé ?",
@@ -1550,11 +1567,15 @@
"reset_password": "Réinitialiser le mot de passe", "reset_password": "Réinitialiser le mot de passe",
"reset_people_visibility": "Réinitialiser la visibilité des personnes", "reset_people_visibility": "Réinitialiser la visibilité des personnes",
"reset_pin_code": "Réinitialiser le code PIN", "reset_pin_code": "Réinitialiser le code PIN",
"reset_sqlite": "Réinitialiser la base de données SQLite",
"reset_sqlite_confirmation": "Êtes vous sur que vous voulez réinitialiser la base de données SQLite? Vous devrez vous déconnecter and vous reconnecter à nouveau pour re-synchroniser les données",
"reset_sqlite_success": "La base de données SQLite à été réinitialisé avec succès",
"reset_to_default": "Rétablir les valeurs par défaut", "reset_to_default": "Rétablir les valeurs par défaut",
"resolve_duplicates": "Résoudre les doublons", "resolve_duplicates": "Résoudre les doublons",
"resolved_all_duplicates": "Résolution de tous les doublons", "resolved_all_duplicates": "Résolution de tous les doublons",
"restore": "Restaurer", "restore": "Restaurer",
"restore_all": "Tout restaurer", "restore_all": "Tout restaurer",
"restore_trash_action_prompt": "{count} restauré de la corbeille",
"restore_user": "Restaurer l'utilisateur", "restore_user": "Restaurer l'utilisateur",
"restored_asset": "Média restauré", "restored_asset": "Média restauré",
"resume": "Reprendre", "resume": "Reprendre",
@@ -1563,6 +1584,7 @@
"role": "Rôle", "role": "Rôle",
"role_editor": "Éditeur", "role_editor": "Éditeur",
"role_viewer": "Visionneuse", "role_viewer": "Visionneuse",
"running": "En marche",
"save": "Sauvegarder", "save": "Sauvegarder",
"save_to_gallery": "Enregistrer", "save_to_gallery": "Enregistrer",
"saved_api_key": "Clé API sauvegardée", "saved_api_key": "Clé API sauvegardée",
@@ -1816,6 +1838,7 @@
"storage_quota": "Quota de stockage", "storage_quota": "Quota de stockage",
"storage_usage": "{used} sur {available} utilisé", "storage_usage": "{used} sur {available} utilisé",
"submit": "Soumettre", "submit": "Soumettre",
"success": "Réussi",
"suggestions": "Suggestions", "suggestions": "Suggestions",
"sunrise_on_the_beach": "Lever de soleil sur la plage", "sunrise_on_the_beach": "Lever de soleil sur la plage",
"support": "Soutenir", "support": "Soutenir",
@@ -1825,6 +1848,8 @@
"sync": "Synchroniser", "sync": "Synchroniser",
"sync_albums": "Synchroniser dans des albums", "sync_albums": "Synchroniser dans des albums",
"sync_albums_manual_subtitle": "Synchroniser toutes les vidéos et photos envoyées dans les albums sélectionnés", "sync_albums_manual_subtitle": "Synchroniser toutes les vidéos et photos envoyées dans les albums sélectionnés",
"sync_local": "Synchronisation locale",
"sync_remote": "Synchronisation à distance",
"sync_upload_album_setting_subtitle": "Créez et envoyez vos photos et vidéos dans les albums sélectionnés sur Immich", "sync_upload_album_setting_subtitle": "Créez et envoyez vos photos et vidéos dans les albums sélectionnés sur Immich",
"tag": "Étiquette", "tag": "Étiquette",
"tag_assets": "Étiqueter les médias", "tag_assets": "Étiqueter les médias",
@@ -1835,6 +1860,7 @@
"tag_updated": "Étiquette mise à jour: {tag}", "tag_updated": "Étiquette mise à jour: {tag}",
"tagged_assets": "Étiquette ajoutée à {count, plural, one {# média} other {# médias}}", "tagged_assets": "Étiquette ajoutée à {count, plural, one {# média} other {# médias}}",
"tags": "Étiquettes", "tags": "Étiquettes",
"tap_to_run_job": "Appuyez pour démarrer la tâche",
"template": "Modèle", "template": "Modèle",
"theme": "Thème", "theme": "Thème",
"theme_selection": "Sélection du thème", "theme_selection": "Sélection du thème",
@@ -1915,6 +1941,7 @@
"updated_password": "Mot de passe mis à jour", "updated_password": "Mot de passe mis à jour",
"upload": "Envoyer", "upload": "Envoyer",
"upload_concurrency": "Envois simultanés", "upload_concurrency": "Envois simultanés",
"upload_details": "Uploader les details",
"upload_dialog_info": "Voulez-vous sauvegarder la sélection vers le serveur?", "upload_dialog_info": "Voulez-vous sauvegarder la sélection vers le serveur?",
"upload_dialog_title": "Envoyer le média", "upload_dialog_title": "Envoyer le média",
"upload_errors": "L'envoi s'est complété avec {count, plural, one {# erreur} other {# erreurs}}. Rafraîchissez la page pour voir les nouveaux médias envoyés.", "upload_errors": "L'envoi s'est complété avec {count, plural, one {# erreur} other {# erreurs}}. Rafraîchissez la page pour voir les nouveaux médias envoyés.",
@@ -1965,6 +1992,7 @@
"view_album": "Afficher l'album", "view_album": "Afficher l'album",
"view_all": "Voir tout", "view_all": "Voir tout",
"view_all_users": "Voir tous les utilisateurs", "view_all_users": "Voir tous les utilisateurs",
"view_details": "Voir les détails",
"view_in_timeline": "Voir dans la vue chronologique", "view_in_timeline": "Voir dans la vue chronologique",
"view_link": "Voir le lien", "view_link": "Voir le lien",
"view_links": "Voir les liens", "view_links": "Voir les liens",
+32 -26
View File
@@ -140,7 +140,7 @@
"machine_learning_smart_search_description": "Képek szemantikai keresése CLIP beágyazások segítségével", "machine_learning_smart_search_description": "Képek szemantikai keresése CLIP beágyazások segítségével",
"machine_learning_smart_search_enabled": "Okos keresés engedélyezése", "machine_learning_smart_search_enabled": "Okos keresés engedélyezése",
"machine_learning_smart_search_enabled_description": "Ha ki van kapcsolva, a képek nem lesznek átalakítva okos kereséshez.", "machine_learning_smart_search_enabled_description": "Ha ki van kapcsolva, a képek nem lesznek átalakítva okos kereséshez.",
"machine_learning_url_description": "Gépi tanulás szerver URL címe. Ha többi, mint egy URL van megadva, mindegyik szervert egyenként próbálja meg, amíg az egyik sikeresen nem válaszol, sorrendben az elsőtől az utólsóig. A nem válaszoló szervereket átmenetileg figyelmen kívül hagyja, amíg újra online nem lesznek.", "machine_learning_url_description": "Gépi tanulás szerver URL címe. Ha többi, mint egy URL van megadva, mindegyik szervert egyenként próbálja meg, amíg az egyik sikeresen nem válaszol, sorrendben az elsőtől az utólsóig. A nem elérhető szervereket átmenetileg figyelmen kívül lesznek hagyva, amíg újra online nem lesznek.",
"manage_concurrency": "Párhuzamos Feladatok Kezelése", "manage_concurrency": "Párhuzamos Feladatok Kezelése",
"manage_log_settings": "Naplózási beállítások kezelése", "manage_log_settings": "Naplózási beállítások kezelése",
"map_dark_style": "Sötét stílus", "map_dark_style": "Sötét stílus",
@@ -166,6 +166,12 @@
"metadata_settings_description": "Metaadat beállítások kezelése", "metadata_settings_description": "Metaadat beállítások kezelése",
"migration_job": "Migrálás", "migration_job": "Migrálás",
"migration_job_description": "Az elemek és arcok bélyegképeinek migrálása a legújabb mappastruktúrába", "migration_job_description": "Az elemek és arcok bélyegképeinek migrálása a legújabb mappastruktúrába",
"nightly_tasks_cluster_faces_setting_description": "Arcfelismerés futtatása az újonnan érzékelt arcokon",
"nightly_tasks_database_cleanup_setting": "Adatbázis-tisztítási feladatok",
"nightly_tasks_database_cleanup_setting_description": "A régi, lejárt adatok törlése az adatbázisból",
"nightly_tasks_generate_memories_setting": "Emlékek generálása",
"nightly_tasks_generate_memories_setting_description": "Új emlékek létrehozása elemekből",
"nightly_tasks_missing_thumbnails_setting": "Hiányzó indexképek generálása",
"no_paths_added": "Nincs megadva elérési útvonal", "no_paths_added": "Nincs megadva elérési útvonal",
"no_pattern_added": "Nincs megadva minta (pattern)", "no_pattern_added": "Nincs megadva minta (pattern)",
"note_apply_storage_label_previous_assets": "Megjegyzés: Ha a korábban feltöltött elemekhez is szeretne Tárhely Címkéket társítani, akkor futtassa ezt", "note_apply_storage_label_previous_assets": "Megjegyzés: Ha a korábban feltöltött elemekhez is szeretne Tárhely Címkéket társítani, akkor futtassa ezt",
@@ -360,7 +366,7 @@
"advanced_settings_enable_alternate_media_filter_subtitle": "Ezzel a beállítással a szinkronizálás során alternatív kritériumok alapján szűrheted a fájlokat. Csak akkor próbáld ki, ha problémáid vannak azzal, hogy az alkalmazás nem ismeri fel az összes albumot.", "advanced_settings_enable_alternate_media_filter_subtitle": "Ezzel a beállítással a szinkronizálás során alternatív kritériumok alapján szűrheted a fájlokat. Csak akkor próbáld ki, ha problémáid vannak azzal, hogy az alkalmazás nem ismeri fel az összes albumot.",
"advanced_settings_enable_alternate_media_filter_title": "[KÍSÉRLETI] Alternatív eszköz album szinkronizálási szűrő használata", "advanced_settings_enable_alternate_media_filter_title": "[KÍSÉRLETI] Alternatív eszköz album szinkronizálási szűrő használata",
"advanced_settings_log_level_title": "Naplózás szintje: {level}", "advanced_settings_log_level_title": "Naplózás szintje: {level}",
"advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő bélyegképeket. Ez a beállítás inkább a távoli képeket tölti be helyettük.", "advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő indexképeket. Ez a beállítás inkább a távoli képeket (a szerverről) tölti be helyettük.",
"advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése", "advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése",
"advanced_settings_proxy_headers_subtitle": "Add meg azokat a proxy fejléceket, amiket az app elküldjön minden hálózati kérésnél", "advanced_settings_proxy_headers_subtitle": "Add meg azokat a proxy fejléceket, amiket az app elküldjön minden hálózati kérésnél",
"advanced_settings_proxy_headers_title": "Proxy Fejlécek", "advanced_settings_proxy_headers_title": "Proxy Fejlécek",
@@ -517,7 +523,7 @@
"backup_controller_page_background_is_on": "Automatikus mentés a háttérben be van kapcsolva", "backup_controller_page_background_is_on": "Automatikus mentés a háttérben be van kapcsolva",
"backup_controller_page_background_turn_off": "Háttérszolgáltatás kikapcsolása", "backup_controller_page_background_turn_off": "Háttérszolgáltatás kikapcsolása",
"backup_controller_page_background_turn_on": "Háttérszolgáltatás bekapcsolása", "backup_controller_page_background_turn_on": "Háttérszolgáltatás bekapcsolása",
"backup_controller_page_background_wifi": "Csak WiFi-n", "backup_controller_page_background_wifi": "Csak Wi-Fi-n",
"backup_controller_page_backup": "Mentés", "backup_controller_page_backup": "Mentés",
"backup_controller_page_backup_selected": "Kiválasztva: ", "backup_controller_page_backup_selected": "Kiválasztva: ",
"backup_controller_page_backup_sub": "Mentett fotók és videók", "backup_controller_page_backup_sub": "Mentett fotók és videók",
@@ -551,8 +557,8 @@
"backup_setting_subtitle": "A háttérben és előtérben mentés beállításainak kezelése", "backup_setting_subtitle": "A háttérben és előtérben mentés beállításainak kezelése",
"backward": "Visszafele", "backward": "Visszafele",
"biometric_auth_enabled": "Biometrikus azonosítás engedélyezve", "biometric_auth_enabled": "Biometrikus azonosítás engedélyezve",
"biometric_locked_out": "A biometrikus azonosításból kizárva", "biometric_locked_out": "Ki vagy zárva a biometrikus azonosításból",
"biometric_no_options": "A biometrikus azonosítás nem elérhető", "biometric_no_options": "Nincsen elérhető biometrikus azonosítás",
"biometric_not_available": "Biometrikus azonosítás ezen az eszközön nem elérhető", "biometric_not_available": "Biometrikus azonosítás ezen az eszközön nem elérhető",
"birthdate_saved": "Születésnap elmentve", "birthdate_saved": "Születésnap elmentve",
"birthdate_set_description": "A születés napját a rendszer arra használja, hogy kiírja, hogy a fénykép készítésekor a személy hány éves volt.", "birthdate_set_description": "A születés napját a rendszer arra használja, hogy kiírja, hogy a fénykép készítésekor a személy hány éves volt.",
@@ -642,7 +648,7 @@
"confirm_keep_this_delete_others": "Minden más elem a készletben törlésre kerül, kivéve ezt az elemet. Biztosan folytatni szeretnéd?", "confirm_keep_this_delete_others": "Minden más elem a készletben törlésre kerül, kivéve ezt az elemet. Biztosan folytatni szeretnéd?",
"confirm_new_pin_code": "Új PIN kód megerősítése", "confirm_new_pin_code": "Új PIN kód megerősítése",
"confirm_password": "Jelszó megerősítése", "confirm_password": "Jelszó megerősítése",
"confirm_tag_face": "Szeretnéd ezt az arcot {name}-ként megjelölni?", "confirm_tag_face": "Szeretnéd ezt az arcot {name}-nak/nek megjelölni?",
"confirm_tag_face_unnamed": "Szeretnéd ezt az arcot megjelölni?", "confirm_tag_face_unnamed": "Szeretnéd ezt az arcot megjelölni?",
"connected_device": "Kapcsolt eszköz", "connected_device": "Kapcsolt eszköz",
"connected_to": "Kapcsolódva", "connected_to": "Kapcsolódva",
@@ -770,7 +776,7 @@
"download_started": "Letöltés megkezdve", "download_started": "Letöltés megkezdve",
"download_sucess": "Sikeres letöltés", "download_sucess": "Sikeres letöltés",
"download_sucess_android": "Média letöltve a DCIM/Immich mappába", "download_sucess_android": "Média letöltve a DCIM/Immich mappába",
"download_waiting_to_retry": "Várakozás újrapróbálkozáshoz", "download_waiting_to_retry": "Várás az újrapróbálkozásra",
"downloading": "Letöltés", "downloading": "Letöltés",
"downloading_asset_filename": "{filename} elem letöltése", "downloading_asset_filename": "{filename} elem letöltése",
"downloading_media": "Média letöltése", "downloading_media": "Média letöltése",
@@ -816,7 +822,7 @@
"enqueued": "Sorba állítva", "enqueued": "Sorba állítva",
"enter_wifi_name": "Add meg a Wi-Fi hálózat nevét", "enter_wifi_name": "Add meg a Wi-Fi hálózat nevét",
"enter_your_pin_code": "Add meg a jelszavad", "enter_your_pin_code": "Add meg a jelszavad",
"enter_your_pin_code_subtitle": "Add meg a jelszavad a zárolt mappa megnyitásához", "enter_your_pin_code_subtitle": "Add meg a PIN kódodat a zárolt mappa megnyitásához",
"error": "Hiba", "error": "Hiba",
"error_change_sort_album": "Album sorbarendezésének megváltoztatása sikertelen", "error_change_sort_album": "Album sorbarendezésének megváltoztatása sikertelen",
"error_delete_face": "Hiba az arc törlése során", "error_delete_face": "Hiba az arc törlése során",
@@ -916,7 +922,7 @@
"unable_to_remove_partner": "Partner eltávolítása sikertelen", "unable_to_remove_partner": "Partner eltávolítása sikertelen",
"unable_to_remove_reaction": "Reakció eltávolítása sikertelen", "unable_to_remove_reaction": "Reakció eltávolítása sikertelen",
"unable_to_reset_password": "Jelszó visszaállítása sikertelen", "unable_to_reset_password": "Jelszó visszaállítása sikertelen",
"unable_to_reset_pin_code": "Jelszó visszaállítása sikertelen", "unable_to_reset_pin_code": "PIN kód visszaállítása sikertelen",
"unable_to_resolve_duplicate": "Duplikátum feloldása sikertelen", "unable_to_resolve_duplicate": "Duplikátum feloldása sikertelen",
"unable_to_restore_assets": "Elemek visszaállítása sikertelen", "unable_to_restore_assets": "Elemek visszaállítása sikertelen",
"unable_to_restore_trash": "Az összes elem visszaállítása sikertelen", "unable_to_restore_trash": "Az összes elem visszaállítása sikertelen",
@@ -988,7 +994,7 @@
"filetype": "Fájltípus", "filetype": "Fájltípus",
"filter": "Szűrő", "filter": "Szűrő",
"filter_people": "Személyek szűrése", "filter_people": "Személyek szűrése",
"filter_places": "Helyek szűrése", "filter_places": "Helyszínek szűrése",
"find_them_fast": "Név alapján kereséssel gyorsan megtalálhatóak", "find_them_fast": "Név alapján kereséssel gyorsan megtalálhatóak",
"fix_incorrect_match": "Hibás találat javítása", "fix_incorrect_match": "Hibás találat javítása",
"folder": "Mappa", "folder": "Mappa",
@@ -1029,9 +1035,9 @@
"hide_person": "Személy elrejtése", "hide_person": "Személy elrejtése",
"hide_unnamed_people": "Név nélküli személyek elrejtése", "hide_unnamed_people": "Név nélküli személyek elrejtése",
"home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.", "home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.",
"home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni, kihagyás", "home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni, ki lesznek hagyva",
"home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.", "home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.",
"home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, kihagyás", "home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, ki lesznek hagyva",
"home_page_archive_err_local": "Helyi elemek archiválása még nem támogatott, úgyhogy kihagyjuk", "home_page_archive_err_local": "Helyi elemek archiválása még nem támogatott, úgyhogy kihagyjuk",
"home_page_archive_err_partner": "Partner elemeit nem lehet archiválni, úgyhogy kihagyjuk", "home_page_archive_err_partner": "Partner elemeit nem lehet archiválni, úgyhogy kihagyjuk",
"home_page_building_timeline": "Idővonal összeállítása", "home_page_building_timeline": "Idővonal összeállítása",
@@ -1040,7 +1046,7 @@
"home_page_favorite_err_local": "Helyi elemeket még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk", "home_page_favorite_err_local": "Helyi elemeket még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk",
"home_page_favorite_err_partner": "Partner elemeit még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk", "home_page_favorite_err_partner": "Partner elemeit még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk",
"home_page_first_time_notice": "Ha most használod először az alkalmazást, a fotók és videók megjelenítéséhez az idővonaladon, állítsd be, hogy melyik albumaidról készüljön biztonsági mentés", "home_page_first_time_notice": "Ha most használod először az alkalmazást, a fotók és videók megjelenítéséhez az idővonaladon, állítsd be, hogy melyik albumaidról készüljön biztonsági mentés",
"home_page_locked_error_local": "Helyi elemek nem mozgathatóak a zárolt mappába, átugorva", "home_page_locked_error_local": "A Helyi elemek nem mozgathatóak a zárolt mappába, ki lesznek hagyva",
"home_page_locked_error_partner": "Partner elemek nem mozgathatóak a zárolt mappába, átugorva", "home_page_locked_error_partner": "Partner elemek nem mozgathatóak a zárolt mappába, átugorva",
"home_page_share_err_local": "Helyi elemekről nem lehet megosztott linket készíteni, úgyhogy kihagyjuk", "home_page_share_err_local": "Helyi elemekről nem lehet megosztott linket készíteni, úgyhogy kihagyjuk",
"home_page_upload_err_limit": "Csak 30 elemet tudsz egyszerre feltölteni, úgyhogy kihagyjuk", "home_page_upload_err_limit": "Csak 30 elemet tudsz egyszerre feltölteni, úgyhogy kihagyjuk",
@@ -1087,10 +1093,10 @@
"invite_people": "Személyek Meghívása", "invite_people": "Személyek Meghívása",
"invite_to_album": "Meghívás az albumba", "invite_to_album": "Meghívás az albumba",
"ios_debug_info_last_sync_at": "Utoljára szinkronizálva {dateTime}", "ios_debug_info_last_sync_at": "Utoljára szinkronizálva {dateTime}",
"ios_debug_info_no_processes_queued": "Nincs sorba állított hátterfolyamat", "ios_debug_info_no_processes_queued": "Nincs a sorban háttérfolyamat jelenleg",
"ios_debug_info_no_sync_yet": "Még nem futott szinkronizáló háttérfolyamat", "ios_debug_info_no_sync_yet": "Még nem futott szinkronizáló háttérfolyamat",
"ios_debug_info_processes_queued": "{count, plural, one {{count} háttérfolyamat előkészítve} other {{count} háttérfolyamat előkészítve}}", "ios_debug_info_processes_queued": "{count, plural, one {{count} háttérfolyamat előkészítve} other {{count} háttérfolyamat előkészítve}}",
"ios_debug_info_processing_ran_at": "Feldolgozás futott {dateTime}", "ios_debug_info_processing_ran_at": "A feldolgozás ekkor futott: {dateTime}",
"items_count": "{count, plural, other {# elem}}", "items_count": "{count, plural, other {# elem}}",
"jobs": "Feladatok", "jobs": "Feladatok",
"keep": "Megtart", "keep": "Megtart",
@@ -1099,7 +1105,7 @@
"kept_this_deleted_others": "Ez az elem és a töröltek meg lettek hagyva {count, plural, one {# asset} other {# assets}}", "kept_this_deleted_others": "Ez az elem és a töröltek meg lettek hagyva {count, plural, one {# asset} other {# assets}}",
"keyboard_shortcuts": "Billentyűparancsok", "keyboard_shortcuts": "Billentyűparancsok",
"language": "Nyelv", "language": "Nyelv",
"language_no_results_subtitle": "Próbáld a keresésed módosítását", "language_no_results_subtitle": "Próbáld módosítani a szavaidat a keresésnél",
"language_search_hint": "Nyelvek keresése...", "language_search_hint": "Nyelvek keresése...",
"language_setting_description": "Válaszd ki preferált nyelvet", "language_setting_description": "Válaszd ki preferált nyelvet",
"last_seen": "Utoljára láttuk", "last_seen": "Utoljára láttuk",
@@ -1129,7 +1135,7 @@
"local_network": "Helyi hálózat", "local_network": "Helyi hálózat",
"local_network_sheet_info": "Az alkalmazés ezen az URL címen fogja elérni a szervert, ha a megadott WiFi hálózathoz van csatlankozva", "local_network_sheet_info": "Az alkalmazés ezen az URL címen fogja elérni a szervert, ha a megadott WiFi hálózathoz van csatlankozva",
"location_permission": "Helymeghatározási engedély", "location_permission": "Helymeghatározási engedély",
"location_permission_content": "Hálózatok automatikus váltásához az Immich-nek szüksége van a pontos helymeghatározásra, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét", "location_permission_content": "A Hálózatok automatikus váltásához az Immich-nek szüksége van a pontos helymeghatározásra, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét",
"location_picker_choose_on_map": "Válassz a térképen", "location_picker_choose_on_map": "Válassz a térképen",
"location_picker_latitude_error": "Érvényes szélességi kört írj be", "location_picker_latitude_error": "Érvényes szélességi kört írj be",
"location_picker_latitude_hint": "Ide írd a szélességi kört", "location_picker_latitude_hint": "Ide írd a szélességi kört",
@@ -1139,7 +1145,7 @@
"locked_folder": "Zárolt mappa", "locked_folder": "Zárolt mappa",
"log_out": "Kijelentkezés", "log_out": "Kijelentkezés",
"log_out_all_devices": "Kijelentkezés Minden Eszközön", "log_out_all_devices": "Kijelentkezés Minden Eszközön",
"logged_in_as": "{user}-ként belépve", "logged_in_as": "Belépve: {user} néven",
"logged_out_all_devices": "Minden eszköz kijelentkeztetve", "logged_out_all_devices": "Minden eszköz kijelentkeztetve",
"logged_out_device": "Eszköz kijelentkeztetve", "logged_out_device": "Eszköz kijelentkeztetve",
"login": "Bejelentkezés", "login": "Bejelentkezés",
@@ -1234,9 +1240,9 @@
"monthly_title_text_date_format": "y MMMM", "monthly_title_text_date_format": "y MMMM",
"more": "Továbbiak", "more": "Továbbiak",
"move": "Áthelyezés", "move": "Áthelyezés",
"move_off_locked_folder": "Zárolt mappából kivonás", "move_off_locked_folder": "Átmozgatás a zárolt mappából",
"move_to_locked_folder": "Áthelyezés a zárolt mappába", "move_to_locked_folder": "Áthelyezés a zárolt mappába",
"move_to_locked_folder_confirmation": "Ezek a képek és videók az összes albumból kikerülnek, és csak a zárolt mappából lesznek elérhetőek", "move_to_locked_folder_confirmation": "Ezek a képek és videók az összes albumból kikerülnek, és csak a zárolt mappában lesznek elérhetőek",
"moved_to_archive": "{count, plural, one {# Elem} other {# Elemek}} archiválva", "moved_to_archive": "{count, plural, one {# Elem} other {# Elemek}} archiválva",
"moved_to_library": "{count, plural, one {# Elem} other {# Elemek}} másik könyvtárba költöztetve", "moved_to_library": "{count, plural, one {# Elem} other {# Elemek}} másik könyvtárba költöztetve",
"moved_to_trash": "Áthelyezve a lomtárba", "moved_to_trash": "Áthelyezve a lomtárba",
@@ -1254,7 +1260,7 @@
"new_password": "Új jelszó", "new_password": "Új jelszó",
"new_person": "Új személy", "new_person": "Új személy",
"new_pin_code": "Új PIN kód", "new_pin_code": "Új PIN kód",
"new_pin_code_subtitle": "Ez az első alkalom hogy megnyitod a zárolt mappát. Hozz létre egy jelszót az oldal biztosítására", "new_pin_code_subtitle": "Ez az első alkalom hogy megnyitod a zárolt mappát. Hozz létre egy jelszót a mappa biztonságos eléréséhez",
"new_user_created": "Új felhasználó létrehozva", "new_user_created": "Új felhasználó létrehozva",
"new_version_available": "ÚJ VERZIÓ ÉRHETŐ EL", "new_version_available": "ÚJ VERZIÓ ÉRHETŐ EL",
"newest_first": "Legújabb először", "newest_first": "Legújabb először",
@@ -1283,7 +1289,7 @@
"not_selected": "Nincs kiválasztva", "not_selected": "Nincs kiválasztva",
"note_apply_storage_label_to_previously_uploaded assets": "Megjegyzés: a korábban feltöltött elemek Tárhely Címkézéséhez futtasd a(z)", "note_apply_storage_label_to_previously_uploaded assets": "Megjegyzés: a korábban feltöltött elemek Tárhely Címkézéséhez futtasd a(z)",
"notes": "Megjegyzések", "notes": "Megjegyzések",
"nothing_here_yet": "Itt még nincs semmi", "nothing_here_yet": "Még semmi sincs itt",
"notification_permission_dialog_content": "Az értesítések bekapcsolásához a Beállítások menüben válaszd ki az Engedélyezés-t.", "notification_permission_dialog_content": "Az értesítések bekapcsolásához a Beállítások menüben válaszd ki az Engedélyezés-t.",
"notification_permission_list_tile_content": "Értesítések engedélyezése.", "notification_permission_list_tile_content": "Értesítések engedélyezése.",
"notification_permission_list_tile_enable_button": "Értesítések Bekapcsolása", "notification_permission_list_tile_enable_button": "Értesítések Bekapcsolása",
@@ -1293,7 +1299,7 @@
"notifications_setting_description": "Értesítések kezelése", "notifications_setting_description": "Értesítések kezelése",
"oauth": "OAuth", "oauth": "OAuth",
"official_immich_resources": "Hivatalos Immich Források", "official_immich_resources": "Hivatalos Immich Források",
"offline": "Offline", "offline": "Nem elérhető (offline)",
"ok": "Rendben", "ok": "Rendben",
"oldest_first": "Legrégebbi először", "oldest_first": "Legrégebbi először",
"on_this_device": "Ezen az eszközön", "on_this_device": "Ezen az eszközön",
@@ -1303,7 +1309,7 @@
"onboarding_theme_description": "Válassz egy színtémát. Ezt bármikor megváltoztathatod a beállításokban.", "onboarding_theme_description": "Válassz egy színtémát. Ezt bármikor megváltoztathatod a beállításokban.",
"onboarding_user_welcome_description": "Kezdjünk bele!", "onboarding_user_welcome_description": "Kezdjünk bele!",
"onboarding_welcome_user": "Üdvözöllek {user}", "onboarding_welcome_user": "Üdvözöllek {user}",
"online": "Online", "online": "Online (elérhető)",
"only_favorites": "Csak kedvencek", "only_favorites": "Csak kedvencek",
"open": "Nyitva", "open": "Nyitva",
"open_in_map_view": "Megnyitás térkép nézetben", "open_in_map_view": "Megnyitás térkép nézetben",
@@ -1754,7 +1760,7 @@
"stack_select_one_photo": "Válassz egy fő képet a csoportból", "stack_select_one_photo": "Válassz egy fő képet a csoportból",
"stack_selected_photos": "Kiválasztott fényképek csoportosítása", "stack_selected_photos": "Kiválasztott fényképek csoportosítása",
"stacked_assets_count": "{count, plural, other {# elem}} csoportosítva", "stacked_assets_count": "{count, plural, other {# elem}} csoportosítva",
"stacktrace": "Hibaleírás", "stacktrace": "Hiba leírása",
"start": "Elindít", "start": "Elindít",
"start_date": "Kezdő dátum", "start_date": "Kezdő dátum",
"state": "Megye/Állam", "state": "Megye/Állam",
@@ -1882,7 +1888,7 @@
"user_liked": "{user} felhasználónak {type, select, photo {ez a fénykép} video {ez a videó} asset {ez az elem} other {ez}} tetszik", "user_liked": "{user} felhasználónak {type, select, photo {ez a fénykép} video {ez a videó} asset {ez az elem} other {ez}} tetszik",
"user_pin_code_settings": "PIN kód", "user_pin_code_settings": "PIN kód",
"user_pin_code_settings_description": "PIN kód kezelése", "user_pin_code_settings_description": "PIN kód kezelése",
"user_privacy": "Felhasználói biztonság", "user_privacy": "Felhasználói adatvédelem",
"user_purchase_settings": "Megvásárlás", "user_purchase_settings": "Megvásárlás",
"user_purchase_settings_description": "Vásárlás kezelése", "user_purchase_settings_description": "Vásárlás kezelése",
"user_role_set": "{user} felhasználónak {role} jogkör biztosítása", "user_role_set": "{user} felhasználónak {role} jogkör biztosítása",
+9 -1
View File
@@ -169,15 +169,23 @@
"nightly_tasks_cluster_faces_setting_description": "Mulai pengenalan wajah pada semua wajah yang baru saja terdeteksi", "nightly_tasks_cluster_faces_setting_description": "Mulai pengenalan wajah pada semua wajah yang baru saja terdeteksi",
"nightly_tasks_cluster_new_faces_setting": "Kelompokkan semua wajah baru", "nightly_tasks_cluster_new_faces_setting": "Kelompokkan semua wajah baru",
"nightly_tasks_database_cleanup_setting": "Tugas pembersihan basis data", "nightly_tasks_database_cleanup_setting": "Tugas pembersihan basis data",
"nightly_tasks_database_cleanup_setting_description": "Membersihkan data lama, kadaluarsa dari database",
"nightly_tasks_generate_memories_setting": "Buat kenang-kenangan", "nightly_tasks_generate_memories_setting": "Buat kenang-kenangan",
"nightly_tasks_generate_memories_setting_description": "Buat kenang-kenangan baru dari berbagai aset", "nightly_tasks_generate_memories_setting_description": "Buat kenang-kenangan baru dari berbagai aset",
"nightly_tasks_missing_thumbnails_setting": "Membuat thumbnail yang hilang",
"nightly_tasks_missing_thumbnails_setting_description": "Mengantrikan aset tanpa thumbnail untuk pembuatan thumbnail",
"nightly_tasks_settings": "Pengaturan Tugas Malam",
"nightly_tasks_settings_description": "Atur tugas malam",
"nightly_tasks_start_time_setting": "Waktu mulai", "nightly_tasks_start_time_setting": "Waktu mulai",
"nightly_tasks_start_time_setting_description": "Waktu saat server mulai menjalankan tugas malam",
"nightly_tasks_sync_quota_usage_setting": "Sinkronisasi penggunaan kuota",
"nightly_tasks_sync_quota_usage_setting_description": "Pembaruan kuota penyimpanan pengguna, berdasarkan penggunaan sekarang",
"no_paths_added": "Tidak ada jalur yang ditambahkan", "no_paths_added": "Tidak ada jalur yang ditambahkan",
"no_pattern_added": "Tidak ada pola yang ditambahkan", "no_pattern_added": "Tidak ada pola yang ditambahkan",
"note_apply_storage_label_previous_assets": "Catatan: Untuk menerapkan Label Penyimpanan untuk aset yang telah diunggah sebelumnya, jalankan", "note_apply_storage_label_previous_assets": "Catatan: Untuk menerapkan Label Penyimpanan untuk aset yang telah diunggah sebelumnya, jalankan",
"note_cannot_be_changed_later": "CATATAN: Ini tidak akan dapat diubah lagi!", "note_cannot_be_changed_later": "CATATAN: Ini tidak akan dapat diubah lagi!",
"notification_email_from_address": "Dari alamat", "notification_email_from_address": "Dari alamat",
"notification_email_from_address_description": "Alamat surel pengirim, misalnya: \"Server Foto Immich <noreply@example.com>\". Pastikan untuk menggunakan alamat yang diizinkan untuk mengirim email", "notification_email_from_address_description": "Alamat surel pengirim, misalnya: \"Server Foto Immich <noreply@example.com>\". Pastikan untuk menggunakan alamat yang diizinkan untuk mengirim email.",
"notification_email_host_description": "Hos server surel (mis. smtp.immich.app)", "notification_email_host_description": "Hos server surel (mis. smtp.immich.app)",
"notification_email_ignore_certificate_errors": "Abaikan eror sertifikat", "notification_email_ignore_certificate_errors": "Abaikan eror sertifikat",
"notification_email_ignore_certificate_errors_description": "Abaikan eror validasi sertifikat TLS (tidak disarankan)", "notification_email_ignore_certificate_errors_description": "Abaikan eror validasi sertifikat TLS (tidak disarankan)",
+12
View File
@@ -406,6 +406,7 @@
"album_options": "Impostazioni Album", "album_options": "Impostazioni Album",
"album_remove_user": "Rimuovi l'utente?", "album_remove_user": "Rimuovi l'utente?",
"album_remove_user_confirmation": "Sicuro di voler rimuovere l'utente {user}?", "album_remove_user_confirmation": "Sicuro di voler rimuovere l'utente {user}?",
"album_search_not_found": "Nessun album trovato corrispondente alla tua ricerca",
"album_share_no_users": "Sembra che tu abbia condiviso questo album con tutti gli utenti oppure non hai nessun utente con cui condividere.", "album_share_no_users": "Sembra che tu abbia condiviso questo album con tutti gli utenti oppure non hai nessun utente con cui condividere.",
"album_updated": "Album aggiornato", "album_updated": "Album aggiornato",
"album_updated_setting_description": "Ricevi una notifica email quando un album condiviso ha nuovi media", "album_updated_setting_description": "Ricevi una notifica email quando un album condiviso ha nuovi media",
@@ -425,6 +426,7 @@
"albums_default_sort_order": "Ordinamento predefinito degli album", "albums_default_sort_order": "Ordinamento predefinito degli album",
"albums_default_sort_order_description": "Ordine iniziale degli elementi alla creazione di nuovi album.", "albums_default_sort_order_description": "Ordine iniziale degli elementi alla creazione di nuovi album.",
"albums_feature_description": "Raggruppamento di elementi che possono essere condivisi con altri utenti.", "albums_feature_description": "Raggruppamento di elementi che possono essere condivisi con altri utenti.",
"albums_on_device_count": "Album sul dispositivo ({count})",
"all": "Tutti", "all": "Tutti",
"all_albums": "Tutti gli album", "all_albums": "Tutti gli album",
"all_people": "Tutte le persone", "all_people": "Tutte le persone",
@@ -605,6 +607,7 @@
"cancel": "Annulla", "cancel": "Annulla",
"cancel_search": "Annulla ricerca", "cancel_search": "Annulla ricerca",
"canceled": "Annullato", "canceled": "Annullato",
"canceling": "Annullamento",
"cannot_merge_people": "Impossibile unire le persone", "cannot_merge_people": "Impossibile unire le persone",
"cannot_undo_this_action": "Non puoi annullare questa azione!", "cannot_undo_this_action": "Non puoi annullare questa azione!",
"cannot_update_the_description": "Impossibile aggiornare la descrizione", "cannot_update_the_description": "Impossibile aggiornare la descrizione",
@@ -751,6 +754,7 @@
"delete_key": "Elimina chiave", "delete_key": "Elimina chiave",
"delete_library": "Elimina libreria", "delete_library": "Elimina libreria",
"delete_link": "Elimina link", "delete_link": "Elimina link",
"delete_local_action_prompt": "{count} elementi rimossi in locale",
"delete_local_dialog_ok_backed_up_only": "Elimina solo con backup", "delete_local_dialog_ok_backed_up_only": "Elimina solo con backup",
"delete_local_dialog_ok_force": "Elimina comunque", "delete_local_dialog_ok_force": "Elimina comunque",
"delete_others": "Elimina gli altri", "delete_others": "Elimina gli altri",
@@ -764,6 +768,7 @@
"description": "Descrizione", "description": "Descrizione",
"description_input_hint_text": "Aggiungi descrizione...", "description_input_hint_text": "Aggiungi descrizione...",
"description_input_submit_error": "Errore modificare descrizione, controlli I log per maggiori dettagli", "description_input_submit_error": "Errore modificare descrizione, controlli I log per maggiori dettagli",
"deselect_all": "Deseleziona Tutto",
"details": "Dettagli", "details": "Dettagli",
"direction": "Direzione", "direction": "Direzione",
"disabled": "Disabilitato", "disabled": "Disabilitato",
@@ -781,6 +786,7 @@
"documentation": "Documentazione", "documentation": "Documentazione",
"done": "Fatto", "done": "Fatto",
"download": "Scarica", "download": "Scarica",
"download_action_prompt": "Scaricando {count} elementi",
"download_canceled": "Download annullato", "download_canceled": "Download annullato",
"download_complete": "Download completato", "download_complete": "Download completato",
"download_enqueue": "Download in coda", "download_enqueue": "Download in coda",
@@ -837,6 +843,7 @@
"empty_trash": "Svuota cestino", "empty_trash": "Svuota cestino",
"empty_trash_confirmation": "Sei sicuro di volere svuotare il cestino? Questo rimuoverà tutte le risorse nel cestino in modo permanente da Immich.\nNon puoi annullare questa azione!", "empty_trash_confirmation": "Sei sicuro di volere svuotare il cestino? Questo rimuoverà tutte le risorse nel cestino in modo permanente da Immich.\nNon puoi annullare questa azione!",
"enable": "Abilita", "enable": "Abilita",
"enable_backup": "Abilita Backup",
"enable_biometric_auth_description": "Inserire il codice PIN per abilitare l'autenticazione biometrica", "enable_biometric_auth_description": "Inserire il codice PIN per abilitare l'autenticazione biometrica",
"enabled": "Abilitato", "enabled": "Abilitato",
"end_date": "Data Fine", "end_date": "Data Fine",
@@ -1483,6 +1490,7 @@
"purchase_server_description_2": "Stato di Contributore", "purchase_server_description_2": "Stato di Contributore",
"purchase_server_title": "Server", "purchase_server_title": "Server",
"purchase_settings_server_activated": "La chiave del prodotto del server è gestita dall'amministratore", "purchase_settings_server_activated": "La chiave del prodotto del server è gestita dall'amministratore",
"queue_status": "Messi in coda {count}/{total}",
"rating": "Valutazione a stelle", "rating": "Valutazione a stelle",
"rating_clear": "Crea valutazione", "rating_clear": "Crea valutazione",
"rating_count": "{count, plural, one {# stella} other {# stelle}}", "rating_count": "{count, plural, one {# stella} other {# stelle}}",
@@ -1518,6 +1526,7 @@
"remove_custom_date_range": "Rimuovi intervallo data personalizzato", "remove_custom_date_range": "Rimuovi intervallo data personalizzato",
"remove_deleted_assets": "Rimuovi file offline", "remove_deleted_assets": "Rimuovi file offline",
"remove_from_album": "Rimuovere dall'album", "remove_from_album": "Rimuovere dall'album",
"remove_from_album_action_prompt": "{count} elementi rimossi dall'album",
"remove_from_favorites": "Rimuovi dai preferiti", "remove_from_favorites": "Rimuovi dai preferiti",
"remove_from_lock_folder_action_prompt": "{count} elementi rimossi dalla cartella sicura", "remove_from_lock_folder_action_prompt": "{count} elementi rimossi dalla cartella sicura",
"remove_from_locked_folder": "Rimuovi dalla cartella privata", "remove_from_locked_folder": "Rimuovi dalla cartella privata",
@@ -1691,6 +1700,7 @@
"settings_saved": "Impostazioni salvate", "settings_saved": "Impostazioni salvate",
"setup_pin_code": "Configura un codice PIN", "setup_pin_code": "Configura un codice PIN",
"share": "Condivisione", "share": "Condivisione",
"share_action_prompt": "Condivisi {count} elementi",
"share_add_photos": "Aggiungi foto", "share_add_photos": "Aggiungi foto",
"share_assets_selected": "{count} selezionati", "share_assets_selected": "{count} selezionati",
"share_dialog_preparing": "Preparo…", "share_dialog_preparing": "Preparo…",
@@ -1792,6 +1802,7 @@
"sort_title": "Titolo", "sort_title": "Titolo",
"source": "Fonte", "source": "Fonte",
"stack": "Raggruppa", "stack": "Raggruppa",
"stack_action_prompt": "{count} elementi raggruppati",
"stack_duplicates": "Raggruppa i duplicati", "stack_duplicates": "Raggruppa i duplicati",
"stack_select_one_photo": "Seleziona una foto principale per il gruppo", "stack_select_one_photo": "Seleziona una foto principale per il gruppo",
"stack_selected_photos": "Impila foto selezionate", "stack_selected_photos": "Impila foto selezionate",
@@ -1880,6 +1891,7 @@
"unable_to_change_pin_code": "Impossibile cambiare il codice PIN", "unable_to_change_pin_code": "Impossibile cambiare il codice PIN",
"unable_to_setup_pin_code": "Impossibile configurare il codice PIN", "unable_to_setup_pin_code": "Impossibile configurare il codice PIN",
"unarchive": "Annulla l'archiviazione", "unarchive": "Annulla l'archiviazione",
"unarchive_action_prompt": "{count} elementi rimossi dall'Archivio",
"unarchived_count": "{count, plural, other {Non archiviati #}}", "unarchived_count": "{count, plural, other {Non archiviati #}}",
"undo": "Annulla", "undo": "Annulla",
"unfavorite": "Rimuovi preferito", "unfavorite": "Rimuovi preferito",
+11
View File
@@ -707,6 +707,9 @@
"next_memory": "Nākamā atmiņa", "next_memory": "Nākamā atmiņa",
"no": "Nē", "no": "Nē",
"no_albums_message": "Izveido albumu, lai organizētu savas fotogrāfijas un video", "no_albums_message": "Izveido albumu, lai organizētu savas fotogrāfijas un video",
"no_albums_with_name_yet": "Izskatās, ka tev vēl nav albumu ar šādu nosaukumu.",
"no_albums_yet": "Izskatās, ka tev vēl nav neviena albuma.",
"no_archived_assets_message": "Arhivē fotoattēlus un videoklipus, lai paslēptu tos no Fotoattēli skata",
"no_assets_message": "NOKLIKŠĶINIET, LAI AUGŠUPIELĀDĒTU SAVU PIRMO FOTOATTĒLU", "no_assets_message": "NOKLIKŠĶINIET, LAI AUGŠUPIELĀDĒTU SAVU PIRMO FOTOATTĒLU",
"no_assets_to_show": "Nav uzrādāmo aktīvu", "no_assets_to_show": "Nav uzrādāmo aktīvu",
"no_duplicates_found": "Dublikāti netika atrasti.", "no_duplicates_found": "Dublikāti netika atrasti.",
@@ -730,6 +733,10 @@
"official_immich_resources": "Oficiālie Immich resursi", "official_immich_resources": "Oficiālie Immich resursi",
"offline": "Bezsaistē", "offline": "Bezsaistē",
"ok": "Labi", "ok": "Labi",
"onboarding": "Uzņemšana",
"onboarding_locale_description": "Izvēlies vēlamo valodu. To vēlāk var mainīt iestatījumos.",
"onboarding_theme_description": "Izvēlies savas instances krāsu motīvu. To vēlāk var mainīt iestatījumos.",
"onboarding_user_welcome_description": "Sāksim darbu!",
"online": "Tiešsaistē", "online": "Tiešsaistē",
"only_favorites": "Tikai izlase", "only_favorites": "Tikai izlase",
"open_in_map_view": "Atvērt kartes skatā", "open_in_map_view": "Atvērt kartes skatā",
@@ -737,13 +744,16 @@
"open_the_search_filters": "Atvērt meklēšanas filtrus", "open_the_search_filters": "Atvērt meklēšanas filtrus",
"options": "Iestatījumi", "options": "Iestatījumi",
"or": "vai", "or": "vai",
"organize_your_library": "Bibliotēkas organizēšana",
"original": "oriģināls", "original": "oriģināls",
"other": "Citi", "other": "Citi",
"other_devices": "Citas ierīces", "other_devices": "Citas ierīces",
"other_variables": "Citi mainīgie", "other_variables": "Citi mainīgie",
"owned": "Īpašumā", "owned": "Īpašumā",
"owner": "Īpašnieks", "owner": "Īpašnieks",
"partner": "Partneris",
"partner_can_access": "{partner} var piekļūt", "partner_can_access": "{partner} var piekļūt",
"partner_can_access_location": "Fotogrāfiju uzņemšanas vieta",
"partner_list_user_photos": "{user} fotoattēli", "partner_list_user_photos": "{user} fotoattēli",
"partner_list_view_all": "Apskatīt visu", "partner_list_view_all": "Apskatīt visu",
"partner_page_empty_message": "Jūsu fotogrāfijas pagaidām nav kopīgotas ar nevienu partneri.", "partner_page_empty_message": "Jūsu fotogrāfijas pagaidām nav kopīgotas ar nevienu partneri.",
@@ -757,6 +767,7 @@
"password_does_not_match": "Parole nesakrīt", "password_does_not_match": "Parole nesakrīt",
"path": "Ceļš", "path": "Ceļš",
"pause": "Pauzēt", "pause": "Pauzēt",
"pause_memories": "Pauzēt atmiņas",
"paused": "Nopauzēts", "paused": "Nopauzēts",
"people": "Cilvēki", "people": "Cilvēki",
"permission_onboarding_back": "Atpakaļ", "permission_onboarding_back": "Atpakaļ",
+22 -1
View File
@@ -573,6 +573,8 @@
"backup_options_page_title": "Backupinnstillinger", "backup_options_page_title": "Backupinnstillinger",
"backup_setting_subtitle": "Administrer opplastingsinnstillinger for bakgrunn og forgrunn", "backup_setting_subtitle": "Administrer opplastingsinnstillinger for bakgrunn og forgrunn",
"backward": "Bakover", "backward": "Bakover",
"beta_sync": "Beta synkroniseringsstatus",
"beta_sync_subtitle": "Håndter det nye synkroniseringssystemet",
"biometric_auth_enabled": "Biometrisk autentisering aktivert", "biometric_auth_enabled": "Biometrisk autentisering aktivert",
"biometric_locked_out": "Du er låst ute av biometrisk verifisering", "biometric_locked_out": "Du er låst ute av biometrisk verifisering",
"biometric_no_options": "Ingen biometriske valg tilgjengelige", "biometric_no_options": "Ingen biometriske valg tilgjengelige",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Tøm buffer", "cache_settings_clear_cache_button": "Tøm buffer",
"cache_settings_clear_cache_button_title": "Tømmer app-ens buffer. Dette vil ha betydelig innvirkning på appens ytelse inntil bufferen er gjenoppbygd.", "cache_settings_clear_cache_button_title": "Tømmer app-ens buffer. Dette vil ha betydelig innvirkning på appens ytelse inntil bufferen er gjenoppbygd.",
"cache_settings_duplicated_assets_clear_button": "TØM", "cache_settings_duplicated_assets_clear_button": "TØM",
"cache_settings_duplicated_assets_subtitle": "Bilder og videoer som er svartelistet av app'en", "cache_settings_duplicated_assets_subtitle": "Bilder og videoer som er ignorert av app'en",
"cache_settings_duplicated_assets_title": "Dupliserte objekter ({count})", "cache_settings_duplicated_assets_title": "Dupliserte objekter ({count})",
"cache_settings_statistics_album": "Bibliotekminiatyrbilder", "cache_settings_statistics_album": "Bibliotekminiatyrbilder",
"cache_settings_statistics_full": "Originalbilder", "cache_settings_statistics_full": "Originalbilder",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Aktivert haptisk tilbakemelding", "haptic_feedback_switch": "Aktivert haptisk tilbakemelding",
"haptic_feedback_title": "Haptisk tilbakemelding", "haptic_feedback_title": "Haptisk tilbakemelding",
"has_quota": "Kvote", "has_quota": "Kvote",
"hash_asset": "Hash objekter",
"hashed_assets": "Hashede objekter",
"hashing": "Hasher",
"header_settings_add_header_tip": "Legg til header", "header_settings_add_header_tip": "Legg til header",
"header_settings_field_validator_msg": "Verdi kan ikke være null", "header_settings_field_validator_msg": "Verdi kan ikke være null",
"header_settings_header_name_input": "Header navn", "header_settings_header_name_input": "Header navn",
@@ -1083,6 +1088,7 @@
"host": "Vert", "host": "Vert",
"hour": "Time", "hour": "Time",
"id": "ID", "id": "ID",
"idle": "Uvirksom",
"ignore_icloud_photos": "Ignorer iCloud bilder", "ignore_icloud_photos": "Ignorer iCloud bilder",
"ignore_icloud_photos_description": "Bilder som er lagret på iCloud vil ikke lastes opp til Immich", "ignore_icloud_photos_description": "Bilder som er lagret på iCloud vil ikke lastes opp til Immich",
"image": "Bilde", "image": "Bilde",
@@ -1165,7 +1171,9 @@
"list": "Liste", "list": "Liste",
"loading": "Laster", "loading": "Laster",
"loading_search_results_failed": "Klarte ikke å laste inn søkeresultater", "loading_search_results_failed": "Klarte ikke å laste inn søkeresultater",
"local": "Lokal",
"local_asset_cast_failed": "Kan ikke caste et bilde som ikke er lastet opp til serveren", "local_asset_cast_failed": "Kan ikke caste et bilde som ikke er lastet opp til serveren",
"local_assets": "Lokale objekter",
"local_network": "Lokalt nettverk", "local_network": "Lokalt nettverk",
"local_network_sheet_info": "Appen vil koble til serveren via denne URL-en når du bruker det angitte Wi-Fi-nettverket", "local_network_sheet_info": "Appen vil koble til serveren via denne URL-en når du bruker det angitte Wi-Fi-nettverket",
"location_permission": "Stedstillatelse", "location_permission": "Stedstillatelse",
@@ -1322,6 +1330,7 @@
"no_results": "Ingen resultater", "no_results": "Ingen resultater",
"no_results_description": "Prøv et synonym eller mer generelt søkeord", "no_results_description": "Prøv et synonym eller mer generelt søkeord",
"no_shared_albums_message": "Opprett et album for å dele bilder og videoer med personer i nettverket ditt", "no_shared_albums_message": "Opprett et album for å dele bilder og videoer med personer i nettverket ditt",
"no_uploads_in_progress": "Ingen opplasting pågår",
"not_in_any_album": "Ikke i noe album", "not_in_any_album": "Ikke i noe album",
"not_selected": "Ikke valgt", "not_selected": "Ikke valgt",
"note_apply_storage_label_to_previously_uploaded assets": "Merk: For å bruke lagringsetiketten på tidligere opplastede filer, kjør", "note_apply_storage_label_to_previously_uploaded assets": "Merk: For å bruke lagringsetiketten på tidligere opplastede filer, kjør",
@@ -1359,6 +1368,7 @@
"original": "original", "original": "original",
"other": "Annet", "other": "Annet",
"other_devices": "Andre enheter", "other_devices": "Andre enheter",
"other_entities": "Andre objekter",
"other_variables": "Andre variabler", "other_variables": "Andre variabler",
"owned": "Dine", "owned": "Dine",
"owner": "Eier", "owner": "Eier",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Oppdaterer ansikter", "refreshing_faces": "Oppdaterer ansikter",
"refreshing_metadata": "Oppdaterer matadata", "refreshing_metadata": "Oppdaterer matadata",
"regenerating_thumbnails": "Regenererer miniatyrbilder", "regenerating_thumbnails": "Regenererer miniatyrbilder",
"remote": "Eksternt",
"remote_assets": "Eksterne objekter",
"remove": "Fjern", "remove": "Fjern",
"remove_assets_album_confirmation": "Er du sikker på at du fil slette {count, plural, one {# asset} other {# assets}} fra albumet?", "remove_assets_album_confirmation": "Er du sikker på at du fil slette {count, plural, one {# asset} other {# assets}} fra albumet?",
"remove_assets_shared_link_confirmation": "Er du sikker på at du vil slette {count, plural, one {# asset} other {# assets}} fra den delte lenken?", "remove_assets_shared_link_confirmation": "Er du sikker på at du vil slette {count, plural, one {# asset} other {# assets}} fra den delte lenken?",
@@ -1556,11 +1568,15 @@
"reset_password": "Tilbakestill passord", "reset_password": "Tilbakestill passord",
"reset_people_visibility": "Tilbakestill personsynlighet", "reset_people_visibility": "Tilbakestill personsynlighet",
"reset_pin_code": "Resett PINkode", "reset_pin_code": "Resett PINkode",
"reset_sqlite": "Reset SQLite Databasen",
"reset_sqlite_confirmation": "Er du sikker på at du vil resette SQLite databasen? Du blir nødt til å logge ut og inn igjen for å resynkronisere data",
"reset_sqlite_success": "Vellykket resetting av SQLite databasen",
"reset_to_default": "Tilbakestill til standard", "reset_to_default": "Tilbakestill til standard",
"resolve_duplicates": "Løs duplikater", "resolve_duplicates": "Løs duplikater",
"resolved_all_duplicates": "Løste alle duplikater", "resolved_all_duplicates": "Løste alle duplikater",
"restore": "Gjenopprett", "restore": "Gjenopprett",
"restore_all": "Gjenopprett alle", "restore_all": "Gjenopprett alle",
"restore_trash_action_prompt": "{count} gjenopprettet fra søppelbøtten",
"restore_user": "Gjenopprett bruker", "restore_user": "Gjenopprett bruker",
"restored_asset": "Gjenopprettet ressurs", "restored_asset": "Gjenopprettet ressurs",
"resume": "Fortsett", "resume": "Fortsett",
@@ -1569,6 +1585,7 @@
"role": "Rolle", "role": "Rolle",
"role_editor": "Redigerer", "role_editor": "Redigerer",
"role_viewer": "Visning", "role_viewer": "Visning",
"running": "Kjører",
"save": "Lagre", "save": "Lagre",
"save_to_gallery": "Lagre til galleriet", "save_to_gallery": "Lagre til galleriet",
"saved_api_key": "Lagret API-nøkkel", "saved_api_key": "Lagret API-nøkkel",
@@ -1822,6 +1839,7 @@
"storage_quota": "Lagringsplass", "storage_quota": "Lagringsplass",
"storage_usage": "{used} av {available} brukt", "storage_usage": "{used} av {available} brukt",
"submit": "Send inn", "submit": "Send inn",
"success": "Vellykket",
"suggestions": "Forslag", "suggestions": "Forslag",
"sunrise_on_the_beach": "Soloppgang på stranden", "sunrise_on_the_beach": "Soloppgang på stranden",
"support": "Støtte", "support": "Støtte",
@@ -1831,6 +1849,8 @@
"sync": "Synkroniser", "sync": "Synkroniser",
"sync_albums": "Synkroniser albumer", "sync_albums": "Synkroniser albumer",
"sync_albums_manual_subtitle": "Synkroniser alle opplastede videoer og bilder til det valgte backupalbumet", "sync_albums_manual_subtitle": "Synkroniser alle opplastede videoer og bilder til det valgte backupalbumet",
"sync_local": "Synkroniser lokalt",
"sync_remote": "Synkroniser eksternt",
"sync_upload_album_setting_subtitle": "Opprett og last opp dine bilder og videoer til det valgte albumet på Immich", "sync_upload_album_setting_subtitle": "Opprett og last opp dine bilder og videoer til det valgte albumet på Immich",
"tag": "Tagg", "tag": "Tagg",
"tag_assets": "Merk ressurser", "tag_assets": "Merk ressurser",
@@ -1841,6 +1861,7 @@
"tag_updated": "Oppdater merke: {tag}", "tag_updated": "Oppdater merke: {tag}",
"tagged_assets": "Merket {count, plural, one {# asset} other {# assets}}", "tagged_assets": "Merket {count, plural, one {# asset} other {# assets}}",
"tags": "Merker", "tags": "Merker",
"tap_to_run_job": "Trykk for å kjøre jobben",
"template": "Mal", "template": "Mal",
"theme": "Tema", "theme": "Tema",
"theme_selection": "Temavalg", "theme_selection": "Temavalg",
+23 -1
View File
@@ -426,6 +426,7 @@
"albums_default_sort_order": "Standaard sorteervolgorde album", "albums_default_sort_order": "Standaard sorteervolgorde album",
"albums_default_sort_order_description": "Initiële sorteervolgorde bij het maken van nieuwe albums.", "albums_default_sort_order_description": "Initiële sorteervolgorde bij het maken van nieuwe albums.",
"albums_feature_description": "Collectie van assets die je kan delen met andere gebruikers.", "albums_feature_description": "Collectie van assets die je kan delen met andere gebruikers.",
"albums_on_device_count": "Albums op apparaat ({count})",
"all": "Alle", "all": "Alle",
"all_albums": "Alle albums", "all_albums": "Alle albums",
"all_people": "Alle mensen", "all_people": "Alle mensen",
@@ -572,6 +573,8 @@
"backup_options_page_title": "Back-up instellingen", "backup_options_page_title": "Back-up instellingen",
"backup_setting_subtitle": "Beheer achtergrond en voorgrond uploadinstellingen", "backup_setting_subtitle": "Beheer achtergrond en voorgrond uploadinstellingen",
"backward": "Achteruit", "backward": "Achteruit",
"beta_sync": "Beta Sync Status",
"beta_sync_subtitle": "Beheer het nieuwe synchronisatiesysteem",
"biometric_auth_enabled": "Biometrische authenticatie ingeschakeld", "biometric_auth_enabled": "Biometrische authenticatie ingeschakeld",
"biometric_locked_out": "Biometrische authenticatie is vergrendeld", "biometric_locked_out": "Biometrische authenticatie is vergrendeld",
"biometric_no_options": "Geen biometrische opties beschikbaar", "biometric_no_options": "Geen biometrische opties beschikbaar",
@@ -589,7 +592,7 @@
"cache_settings_clear_cache_button": "Cache wissen", "cache_settings_clear_cache_button": "Cache wissen",
"cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.", "cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.",
"cache_settings_duplicated_assets_clear_button": "MAAK VRIJ", "cache_settings_duplicated_assets_clear_button": "MAAK VRIJ",
"cache_settings_duplicated_assets_subtitle": "Foto's en video's op de zwarte lijst van de app", "cache_settings_duplicated_assets_subtitle": "Fotos en video's die de app negeert",
"cache_settings_duplicated_assets_title": "Gedupliceerde assets ({count})", "cache_settings_duplicated_assets_title": "Gedupliceerde assets ({count})",
"cache_settings_statistics_album": "Bibliotheekthumbnails", "cache_settings_statistics_album": "Bibliotheekthumbnails",
"cache_settings_statistics_full": "Volledige afbeeldingen", "cache_settings_statistics_full": "Volledige afbeeldingen",
@@ -1050,6 +1053,9 @@
"haptic_feedback_switch": "Aanraaktrillingen inschakelen", "haptic_feedback_switch": "Aanraaktrillingen inschakelen",
"haptic_feedback_title": "Aanraaktrillingen", "haptic_feedback_title": "Aanraaktrillingen",
"has_quota": "Heeft limiet", "has_quota": "Heeft limiet",
"hash_asset": "Hash asset",
"hashed_assets": "Gehashte assets",
"hashing": "Hashen",
"header_settings_add_header_tip": "Header toevoegen", "header_settings_add_header_tip": "Header toevoegen",
"header_settings_field_validator_msg": "Waarde kan niet leeg zijn", "header_settings_field_validator_msg": "Waarde kan niet leeg zijn",
"header_settings_header_name_input": "Header naam", "header_settings_header_name_input": "Header naam",
@@ -1082,6 +1088,7 @@
"host": "Host", "host": "Host",
"hour": "Uur", "hour": "Uur",
"id": "ID", "id": "ID",
"idle": "Idle",
"ignore_icloud_photos": "Negeer iCloud foto's", "ignore_icloud_photos": "Negeer iCloud foto's",
"ignore_icloud_photos_description": "Foto's die op iCloud zijn opgeslagen, worden niet geüpload naar de Immich server", "ignore_icloud_photos_description": "Foto's die op iCloud zijn opgeslagen, worden niet geüpload naar de Immich server",
"image": "Afbeelding", "image": "Afbeelding",
@@ -1164,7 +1171,9 @@
"list": "Lijst", "list": "Lijst",
"loading": "Laden", "loading": "Laden",
"loading_search_results_failed": "Laden van zoekresultaten mislukt", "loading_search_results_failed": "Laden van zoekresultaten mislukt",
"local": "Lokaal",
"local_asset_cast_failed": "Kan geen asset casten die nog niet geüpload is naar de server", "local_asset_cast_failed": "Kan geen asset casten die nog niet geüpload is naar de server",
"local_assets": "Lokale Assets",
"local_network": "Lokaal netwerk", "local_network": "Lokaal netwerk",
"local_network_sheet_info": "De app maakt verbinding met de server via deze URL wanneer het opgegeven WiFi-netwerk wordt gebruikt", "local_network_sheet_info": "De app maakt verbinding met de server via deze URL wanneer het opgegeven WiFi-netwerk wordt gebruikt",
"location_permission": "Locatietoestemming", "location_permission": "Locatietoestemming",
@@ -1321,6 +1330,7 @@
"no_results": "Geen resultaten", "no_results": "Geen resultaten",
"no_results_description": "Probeer een synoniem of een algemener zoekwoord", "no_results_description": "Probeer een synoniem of een algemener zoekwoord",
"no_shared_albums_message": "Maak een album om foto's en video's te delen met mensen in je netwerk", "no_shared_albums_message": "Maak een album om foto's en video's te delen met mensen in je netwerk",
"no_uploads_in_progress": "Geen uploads bezig",
"not_in_any_album": "Niet in een album", "not_in_any_album": "Niet in een album",
"not_selected": "Niet geselecteerd", "not_selected": "Niet geselecteerd",
"note_apply_storage_label_to_previously_uploaded assets": "Opmerking: om het opslaglabel toe te passen op eerder geüploade assets, voer de volgende taak uit", "note_apply_storage_label_to_previously_uploaded assets": "Opmerking: om het opslaglabel toe te passen op eerder geüploade assets, voer de volgende taak uit",
@@ -1358,6 +1368,7 @@
"original": "origineel", "original": "origineel",
"other": "Overige", "other": "Overige",
"other_devices": "Andere apparaten", "other_devices": "Andere apparaten",
"other_entities": "Andere entities",
"other_variables": "Andere variabelen", "other_variables": "Andere variabelen",
"owned": "Eigenaar", "owned": "Eigenaar",
"owner": "Eigenaar", "owner": "Eigenaar",
@@ -1518,6 +1529,8 @@
"refreshing_faces": "Gezichten aan het vernieuwen", "refreshing_faces": "Gezichten aan het vernieuwen",
"refreshing_metadata": "Metadata aan het vernieuwen", "refreshing_metadata": "Metadata aan het vernieuwen",
"regenerating_thumbnails": "Thumbnails opnieuw aan het genereren", "regenerating_thumbnails": "Thumbnails opnieuw aan het genereren",
"remote": "Remote",
"remote_assets": "Remote Assets",
"remove": "Verwijderen", "remove": "Verwijderen",
"remove_assets_album_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit het album wilt verwijderen?", "remove_assets_album_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit het album wilt verwijderen?",
"remove_assets_shared_link_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit deze gedeelde link wilt verwijderen?", "remove_assets_shared_link_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit deze gedeelde link wilt verwijderen?",
@@ -1555,11 +1568,15 @@
"reset_password": "Wachtwoord resetten", "reset_password": "Wachtwoord resetten",
"reset_people_visibility": "Zichtbaarheid mensen resetten", "reset_people_visibility": "Zichtbaarheid mensen resetten",
"reset_pin_code": "Reset PIN code", "reset_pin_code": "Reset PIN code",
"reset_sqlite": "Reset SQLite Database",
"reset_sqlite_confirmation": "Ben je zeker dat je de SQLite database wilt resetten? Je zal moetenn uitloggen om de data opnieuw te synchroniseren.",
"reset_sqlite_success": "De SQLite database is succesvol gereset",
"reset_to_default": "Resetten naar standaard", "reset_to_default": "Resetten naar standaard",
"resolve_duplicates": "Duplicaten oplossen", "resolve_duplicates": "Duplicaten oplossen",
"resolved_all_duplicates": "Alle duplicaten opgelost", "resolved_all_duplicates": "Alle duplicaten opgelost",
"restore": "Herstellen", "restore": "Herstellen",
"restore_all": "Herstel alle", "restore_all": "Herstel alle",
"restore_trash_action_prompt": "{count} teruggezet uit prullenbak",
"restore_user": "Gebruiker herstellen", "restore_user": "Gebruiker herstellen",
"restored_asset": "Asset hersteld", "restored_asset": "Asset hersteld",
"resume": "Hervatten", "resume": "Hervatten",
@@ -1568,6 +1585,7 @@
"role": "Rol", "role": "Rol",
"role_editor": "Bewerker", "role_editor": "Bewerker",
"role_viewer": "Bekijker", "role_viewer": "Bekijker",
"running": "Actief",
"save": "Opslaan", "save": "Opslaan",
"save_to_gallery": "Opslaan in galerij", "save_to_gallery": "Opslaan in galerij",
"saved_api_key": "API-sleutel opgeslagen", "saved_api_key": "API-sleutel opgeslagen",
@@ -1821,6 +1839,7 @@
"storage_quota": "Opslaglimiet", "storage_quota": "Opslaglimiet",
"storage_usage": "{used} van {available} gebruikt", "storage_usage": "{used} van {available} gebruikt",
"submit": "Verzenden", "submit": "Verzenden",
"success": "Succes",
"suggestions": "Suggesties", "suggestions": "Suggesties",
"sunrise_on_the_beach": "Zonsopkomst op het strand", "sunrise_on_the_beach": "Zonsopkomst op het strand",
"support": "Ondersteuning", "support": "Ondersteuning",
@@ -1830,6 +1849,8 @@
"sync": "Sync", "sync": "Sync",
"sync_albums": "Albums synchroniseren", "sync_albums": "Albums synchroniseren",
"sync_albums_manual_subtitle": "Synchroniseer alle geüploade videos en fotos naar de geselecteerde back-up albums", "sync_albums_manual_subtitle": "Synchroniseer alle geüploade videos en fotos naar de geselecteerde back-up albums",
"sync_local": "Lokaal synchroniseren",
"sync_remote": "Op afstand synchroniseren",
"sync_upload_album_setting_subtitle": "Maak en upload je foto's en video's naar de geselecteerde albums op Immich", "sync_upload_album_setting_subtitle": "Maak en upload je foto's en video's naar de geselecteerde albums op Immich",
"tag": "Tag", "tag": "Tag",
"tag_assets": "Assets taggen", "tag_assets": "Assets taggen",
@@ -1840,6 +1861,7 @@
"tag_updated": "Tag bijgewerkt: {tag}", "tag_updated": "Tag bijgewerkt: {tag}",
"tagged_assets": "{count, plural, one {# asset} other {# assets}} getagd", "tagged_assets": "{count, plural, one {# asset} other {# assets}} getagd",
"tags": "Tags", "tags": "Tags",
"tap_to_run_job": "Klik om job te starten",
"template": "Template", "template": "Template",
"theme": "Thema", "theme": "Thema",
"theme_selection": "Thema selectie", "theme_selection": "Thema selectie",
+34 -13
View File
@@ -228,7 +228,7 @@
"password_settings_description": "Управление настройками входа по паролю", "password_settings_description": "Управление настройками входа по паролю",
"paths_validated_successfully": "Все пути успешно прошли проверку", "paths_validated_successfully": "Все пути успешно прошли проверку",
"person_cleanup_job": "Очистка персоны", "person_cleanup_job": "Очистка персоны",
"quota_size_gib": "Размер квоты (ГБ)", "quota_size_gib": "Размер квоты (GiB)",
"refreshing_all_libraries": "Обновление всех библиотек", "refreshing_all_libraries": "Обновление всех библиотек",
"registration": "Регистрация администратора", "registration": "Регистрация администратора",
"registration_description": "Первый зарегистрированный пользователь будет назначен администратором. В дальнейшем этой учетной записи будет доступно создание дополнительных пользователей и управление сервером.", "registration_description": "Первый зарегистрированный пользователь будет назначен администратором. В дальнейшем этой учетной записи будет доступно создание дополнительных пользователей и управление сервером.",
@@ -241,7 +241,7 @@
"server_external_domain_settings": "Внешний домен", "server_external_domain_settings": "Внешний домен",
"server_external_domain_settings_description": "Домен для публичных ссылок, включая http(s)://", "server_external_domain_settings_description": "Домен для публичных ссылок, включая http(s)://",
"server_public_users": "Публичные пользователи", "server_public_users": "Публичные пользователи",
"server_public_users_description": "Отображать всех пользователей (имена и email) для добавления в общие альбомы. Когда отключено, список пользователей будет доступен только администраторам.", "server_public_users_description": "Выводить список пользователей (имена и email) в общих альбомах. Когда отключено, список доступен только администраторам, пользователи смогут делиться только ссылкой.",
"server_settings": "Настройки сервера", "server_settings": "Настройки сервера",
"server_settings_description": "Управление настройками сервера", "server_settings_description": "Управление настройками сервера",
"server_welcome_message": "Приветственное сообщение", "server_welcome_message": "Приветственное сообщение",
@@ -407,7 +407,7 @@
"album_remove_user": "Удалить пользователя?", "album_remove_user": "Удалить пользователя?",
"album_remove_user_confirmation": "Вы уверены, что хотите удалить пользователя {user}?", "album_remove_user_confirmation": "Вы уверены, что хотите удалить пользователя {user}?",
"album_search_not_found": "Не найдено альбомов по вашему запросу", "album_search_not_found": "Не найдено альбомов по вашему запросу",
"album_share_no_users": "Похоже, вы поделились этим альбомом со всеми пользователями или у вас нет пользователей, с которыми можно поделиться.", "album_share_no_users": "Нет доступных пользователей, с которыми можно поделиться альбомом.",
"album_updated": "Альбом обновлён", "album_updated": "Альбом обновлён",
"album_updated_setting_description": "Получать уведомление по электронной почте при добавлении новых ресурсов в общий альбом", "album_updated_setting_description": "Получать уведомление по электронной почте при добавлении новых ресурсов в общий альбом",
"album_user_left": "Вы покинули {album}", "album_user_left": "Вы покинули {album}",
@@ -433,8 +433,8 @@
"all_videos": "Все видео", "all_videos": "Все видео",
"allow_dark_mode": "Разрешить темный режим", "allow_dark_mode": "Разрешить темный режим",
"allow_edits": "Разрешить редактирование", "allow_edits": "Разрешить редактирование",
"allow_public_user_to_download": "Разрешить скачивание публичным пользователям", "allow_public_user_to_download": "Разрешить скачивание",
"allow_public_user_to_upload": "Разрешить публичным пользователям загружать файлы", "allow_public_user_to_upload": "Разрешить добавление файлов",
"alt_text_qr_code": "QR-код", "alt_text_qr_code": "QR-код",
"anti_clockwise": "Против часовой", "anti_clockwise": "Против часовой",
"api_key": "API ключ", "api_key": "API ключ",
@@ -573,6 +573,8 @@
"backup_options_page_title": "Резервное копирование", "backup_options_page_title": "Резервное копирование",
"backup_setting_subtitle": "Настройка активного и фонового резервного копирования", "backup_setting_subtitle": "Настройка активного и фонового резервного копирования",
"backward": "Назад", "backward": "Назад",
"beta_sync": "Статус бета-синхронизации",
"beta_sync_subtitle": "Управление новой системой синхронизации",
"biometric_auth_enabled": "Биометрическая аутентификация включена", "biometric_auth_enabled": "Биометрическая аутентификация включена",
"biometric_locked_out": "Вам закрыт доступ к биометрической аутентификации", "biometric_locked_out": "Вам закрыт доступ к биометрической аутентификации",
"biometric_no_options": "Биометрическая аутентификация недоступна", "biometric_no_options": "Биометрическая аутентификация недоступна",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Очистить кэш", "cache_settings_clear_cache_button": "Очистить кэш",
"cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это негативно повлияет на производительность, пока кэш не будет создан заново.", "cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это негативно повлияет на производительность, пока кэш не будет создан заново.",
"cache_settings_duplicated_assets_clear_button": "ОЧИСТИТЬ", "cache_settings_duplicated_assets_clear_button": "ОЧИСТИТЬ",
"cache_settings_duplicated_assets_subtitle": "Фото и видео, занесенные приложением в черный список", "cache_settings_duplicated_assets_subtitle": "Фото и видео, пропускаемые приложением",
"cache_settings_duplicated_assets_title": "Дублирующиеся объекты ({count})", "cache_settings_duplicated_assets_title": "Дублирующиеся объекты ({count})",
"cache_settings_statistics_album": "Миниатюры библиотеки", "cache_settings_statistics_album": "Миниатюры библиотеки",
"cache_settings_statistics_full": "Полные изображения", "cache_settings_statistics_full": "Полные изображения",
@@ -616,7 +618,7 @@
"change_date": "Изменить дату", "change_date": "Изменить дату",
"change_description": "Изменить описание", "change_description": "Изменить описание",
"change_display_order": "Изменить порядок отображения", "change_display_order": "Изменить порядок отображения",
"change_expiration_time": "Изменить время окончания", "change_expiration_time": "Изменить срок действия",
"change_location": "Изменить местоположение", "change_location": "Изменить местоположение",
"change_name": "Изменить имя", "change_name": "Изменить имя",
"change_name_successfully": "Имя успешно изменено", "change_name_successfully": "Имя успешно изменено",
@@ -692,7 +694,7 @@
"copy_link": "Копировать ссылку", "copy_link": "Копировать ссылку",
"copy_link_to_clipboard": "Скопировать ссылку в буфер обмена", "copy_link_to_clipboard": "Скопировать ссылку в буфер обмена",
"copy_password": "Скопировать пароль", "copy_password": "Скопировать пароль",
"copy_to_clipboard": "Скопировать в буфер обмена", "copy_to_clipboard": "Скопировать настройки в буфер обмена",
"country": "Страна", "country": "Страна",
"cover": "Обложка", "cover": "Обложка",
"covers": "Обложки", "covers": "Обложки",
@@ -830,7 +832,7 @@
"edit_people": "Редактировать людей", "edit_people": "Редактировать людей",
"edit_tag": "Изменить тег", "edit_tag": "Изменить тег",
"edit_title": "Редактировать Заголовок", "edit_title": "Редактировать Заголовок",
"edit_user": "Редактирование пользователя", "edit_user": "Изменить пользователя",
"edited": "Отредактировано", "edited": "Отредактировано",
"editor": "Редактор", "editor": "Редактор",
"editor_close_without_save_prompt": "Изменения не будут сохранены", "editor_close_without_save_prompt": "Изменения не будут сохранены",
@@ -994,7 +996,7 @@
"experimental_settings_subtitle": "Используйте на свой страх и риск!", "experimental_settings_subtitle": "Используйте на свой страх и риск!",
"experimental_settings_title": "Экспериментальные функции", "experimental_settings_title": "Экспериментальные функции",
"expire_after": "Истекает через", "expire_after": "Истекает через",
"expired": "Срок действия истек", "expired": "Срок действия истёк",
"expires_date": "Срок действия до {date}", "expires_date": "Срок действия до {date}",
"explore": "Поиск", "explore": "Поиск",
"explorer": "Проводник", "explorer": "Проводник",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Включить тактильную отдачу", "haptic_feedback_switch": "Включить тактильную отдачу",
"haptic_feedback_title": "Тактильная отдача", "haptic_feedback_title": "Тактильная отдача",
"has_quota": "Квота", "has_quota": "Квота",
"hash_asset": "Хешированный объект",
"hashed_assets": "Хешированные объекты",
"hashing": "Хеширование",
"header_settings_add_header_tip": "Добавить заголовок", "header_settings_add_header_tip": "Добавить заголовок",
"header_settings_field_validator_msg": "Значение не может быть пустым", "header_settings_field_validator_msg": "Значение не может быть пустым",
"header_settings_header_name_input": "Имя заголовка", "header_settings_header_name_input": "Имя заголовка",
@@ -1083,6 +1088,7 @@
"host": "Хост", "host": "Хост",
"hour": "Час", "hour": "Час",
"id": "ID", "id": "ID",
"idle": "В ожидании",
"ignore_icloud_photos": "Пропускать файлы из iCloud", "ignore_icloud_photos": "Пропускать файлы из iCloud",
"ignore_icloud_photos_description": "Не загружать файлы в Immich, если они хранятся в iCloud", "ignore_icloud_photos_description": "Не загружать файлы в Immich, если они хранятся в iCloud",
"image": "Изображения", "image": "Изображения",
@@ -1109,8 +1115,8 @@
"include_archived": "Отображать архив", "include_archived": "Отображать архив",
"include_shared_albums": "Включать общие альбомы", "include_shared_albums": "Включать общие альбомы",
"include_shared_partner_assets": "Включать общие ресурсы партнера", "include_shared_partner_assets": "Включать общие ресурсы партнера",
"individual_share": "Персональный доступ", "individual_share": "Индивидуальная подборка",
"individual_shares": "Индивидуальный доступ", "individual_shares": "Подборки",
"info": "Информация", "info": "Информация",
"interval": { "interval": {
"day_at_onepm": "Каждый день в 13:00", "day_at_onepm": "Каждый день в 13:00",
@@ -1165,7 +1171,9 @@
"list": "Список", "list": "Список",
"loading": "Загрузка", "loading": "Загрузка",
"loading_search_results_failed": "Загрузка результатов поиска не удалась", "loading_search_results_failed": "Загрузка результатов поиска не удалась",
"local": "На устройстве",
"local_asset_cast_failed": "Невозможно транслировать объект, который ещё не загружен на сервер", "local_asset_cast_failed": "Невозможно транслировать объект, который ещё не загружен на сервер",
"local_assets": "Объекты на устройстве",
"local_network": "Локальная сеть", "local_network": "Локальная сеть",
"local_network_sheet_info": "Приложение будет подключаться к серверу по этому адресу, когда устройство подключено к выбранной Wi-Fi сети", "local_network_sheet_info": "Приложение будет подключаться к серверу по этому адресу, когда устройство подключено к выбранной Wi-Fi сети",
"location_permission": "Доступ к местоположению", "location_permission": "Доступ к местоположению",
@@ -1322,6 +1330,7 @@
"no_results": "Нет результатов", "no_results": "Нет результатов",
"no_results_description": "Попробуйте использовать синоним или более общее ключевое слово", "no_results_description": "Попробуйте использовать синоним или более общее ключевое слово",
"no_shared_albums_message": "Создайте альбом для обмена фотографиями и видеозаписями с людьми в вашей сети", "no_shared_albums_message": "Создайте альбом для обмена фотографиями и видеозаписями с людьми в вашей сети",
"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_apply_storage_label_to_previously_uploaded assets": "Примечание: Чтобы применить метку хранилища к ранее загруженным ресурсам, запустите",
@@ -1359,6 +1368,7 @@
"original": "оригинал", "original": "оригинал",
"other": "Другое", "other": "Другое",
"other_devices": "Другие устройства", "other_devices": "Другие устройства",
"other_entities": "Другие объекты",
"other_variables": "Другие переменные", "other_variables": "Другие переменные",
"owned": "Мои", "owned": "Мои",
"owner": "Владелец", "owner": "Владелец",
@@ -1456,7 +1466,7 @@
"profile_drawer_server_out_of_date_minor": "Версия сервера устарела. Пожалуйста, обновите его.", "profile_drawer_server_out_of_date_minor": "Версия сервера устарела. Пожалуйста, обновите его.",
"profile_image_of_user": "Изображение профиля {user}", "profile_image_of_user": "Изображение профиля {user}",
"profile_picture_set": "Фото профиля установлено.", "profile_picture_set": "Фото профиля установлено.",
"public_album": "Публичный альбом", "public_album": "Общий альбом",
"public_share": "Публичный доступ", "public_share": "Публичный доступ",
"purchase_account_info": "Поддержка", "purchase_account_info": "Поддержка",
"purchase_activated_subtitle": "Благодарим вас за поддержку Immich и программного обеспечения с открытым исходным кодом", "purchase_activated_subtitle": "Благодарим вас за поддержку Immich и программного обеспечения с открытым исходным кодом",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Обновление лиц", "refreshing_faces": "Обновление лиц",
"refreshing_metadata": "Обновление метаданных", "refreshing_metadata": "Обновление метаданных",
"regenerating_thumbnails": "Восстановление миниатюр", "regenerating_thumbnails": "Восстановление миниатюр",
"remote": "На сервере",
"remote_assets": "Объекты на сервере",
"remove": "Удалить", "remove": "Удалить",
"remove_assets_album_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из альбома?", "remove_assets_album_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из альбома?",
"remove_assets_shared_link_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из публичного доступа по этой ссылке?", "remove_assets_shared_link_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из публичного доступа по этой ссылке?",
@@ -1556,11 +1568,15 @@
"reset_password": "Сброс пароля", "reset_password": "Сброс пароля",
"reset_people_visibility": "Восстановить видимость людей", "reset_people_visibility": "Восстановить видимость людей",
"reset_pin_code": "Сбросить PIN-код", "reset_pin_code": "Сбросить PIN-код",
"reset_sqlite": "Очистить базу данных SQLite",
"reset_sqlite_confirmation": "Вы уверены, что хотите очистить базу данных SQLite? Вам потребуется выйти из системы и снова войти для повторной синхронизации данных.",
"reset_sqlite_success": "База данных SQLite успешно очищена",
"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} восстановлено из корзины",
"restore_user": "Восстановить пользователя", "restore_user": "Восстановить пользователя",
"restored_asset": "Восстановленный объект", "restored_asset": "Восстановленный объект",
"resume": "Продолжить", "resume": "Продолжить",
@@ -1569,6 +1585,7 @@
"role": "Роль", "role": "Роль",
"role_editor": "Редактор", "role_editor": "Редактор",
"role_viewer": "Зритель", "role_viewer": "Зритель",
"running": "Выполняется",
"save": "Сохранить", "save": "Сохранить",
"save_to_gallery": "Сохранить в галерею", "save_to_gallery": "Сохранить в галерею",
"saved_api_key": "API ключ изменён", "saved_api_key": "API ключ изменён",
@@ -1822,6 +1839,7 @@
"storage_quota": "Квота хранилища", "storage_quota": "Квота хранилища",
"storage_usage": "{used} из {available}", "storage_usage": "{used} из {available}",
"submit": "Подтвердить", "submit": "Подтвердить",
"success": "Успешно",
"suggestions": "Предложения", "suggestions": "Предложения",
"sunrise_on_the_beach": "Восход солнца на пляже", "sunrise_on_the_beach": "Восход солнца на пляже",
"support": "Поддержка", "support": "Поддержка",
@@ -1831,6 +1849,8 @@
"sync": "Синхр.", "sync": "Синхр.",
"sync_albums": "Синхронизировать альбомы", "sync_albums": "Синхронизировать альбомы",
"sync_albums_manual_subtitle": "Синхронизировать все загруженные фото и видео в выбранные альбомы для резервного копирования", "sync_albums_manual_subtitle": "Синхронизировать все загруженные фото и видео в выбранные альбомы для резервного копирования",
"sync_local": "Синхронизировать локально",
"sync_remote": "Синхронизация с сервером",
"sync_upload_album_setting_subtitle": "Создавайте и загружайте свои фотографии и видео в выбранные альбомы на сервер Immich", "sync_upload_album_setting_subtitle": "Создавайте и загружайте свои фотографии и видео в выбранные альбомы на сервер Immich",
"tag": "Тег", "tag": "Тег",
"tag_assets": "Добавить теги", "tag_assets": "Добавить теги",
@@ -1841,6 +1861,7 @@
"tag_updated": "Тег {tag} изменен", "tag_updated": "Тег {tag} изменен",
"tagged_assets": "Тег назначен для {count, plural, one {# объекта} other {# объектов}}", "tagged_assets": "Тег назначен для {count, plural, one {# объекта} other {# объектов}}",
"tags": "Теги", "tags": "Теги",
"tap_to_run_job": "Нажмите для запуска задачи",
"template": "Шаблон", "template": "Шаблон",
"theme": "Тема", "theme": "Тема",
"theme_selection": "Выбор темы", "theme_selection": "Выбор темы",
+69 -48
View File
@@ -45,14 +45,14 @@
"backup_database_enable_description": "Povoliť výpisy z databázy", "backup_database_enable_description": "Povoliť výpisy z databázy",
"backup_keep_last_amount": "Množstvo predchádzajúcich výpisov, ktoré sa majú zachovať", "backup_keep_last_amount": "Množstvo predchádzajúcich výpisov, ktoré sa majú zachovať",
"backup_settings": "Nastavenia výpisu databázy", "backup_settings": "Nastavenia výpisu databázy",
"backup_settings_description": "Správa nastavení výpisu databázy.", "backup_settings_description": "Spravovať nastavenia výpisu databázy.",
"cleared_jobs": "Hotové úlohy pre: {job}", "cleared_jobs": "Hotové úlohy pre: {job}",
"config_set_by_file": "Konfigurácia je v súčasnosti nastavená konfiguračným súborom", "config_set_by_file": "Konfigurácia je v súčasnosti nastavená konfiguračným súborom",
"confirm_delete_library": "Naozaj chcete vymazať knižnicu {library}?", "confirm_delete_library": "Naozaj chcete vymazať knižnicu {library}?",
"confirm_delete_library_assets": "Ste si istí, že chcete vymazať túto knižnicu? Tato operácia nenávratne odstráni {count, plural, one {# zahrnutú položku} few {# zahrnuté položky} other {všetkých # zahrnutých položiek}} z aplikácie Immich. Súbory budú ponechané na disku.", "confirm_delete_library_assets": "Ste si istí, že chcete vymazať túto knižnicu? Tato operácia nenávratne odstráni {count, plural, one {# zahrnutú položku} few {# zahrnuté položky} other {všetkých # zahrnutých položiek}} z aplikácie Immich. Súbory budú ponechané na disku.",
"confirm_email_below": "Pre potvrdenie zadajte \"{email}\" nižšie", "confirm_email_below": "Pre potvrdenie zadajte \"{email}\" nižšie",
"confirm_reprocess_all_faces": "Naozaj chcete spracovať všetky tváre znova? Tento proces vymaže pomenovaných ľudí.", "confirm_reprocess_all_faces": "Naozaj chcete spracovať všetky tváre znova? Tento proces vymaže pomenovaných ľudí.",
"confirm_user_password_reset": "Naozaj chcete resetovať heslo pre {user}?", "confirm_user_password_reset": "Naozaj chcete obnoviť heslo pre {user}?",
"confirm_user_pin_code_reset": "Ste si istí, že chcete opätovne nastaviť PIN kód používateľa {user}?", "confirm_user_pin_code_reset": "Ste si istí, že chcete opätovne nastaviť PIN kód používateľa {user}?",
"create_job": "Vytvoriť úlohu", "create_job": "Vytvoriť úlohu",
"cron_expression": "Výraz cron", "cron_expression": "Výraz cron",
@@ -61,10 +61,10 @@
"disable_login": "Zakázať prihlásenie", "disable_login": "Zakázať prihlásenie",
"duplicate_detection_job_description": "Spustite strojové učenie na položkách pre detekciu podobných obrázkov. Spolieha sa na inteligentné vyhľadávanie", "duplicate_detection_job_description": "Spustite strojové učenie na položkách pre detekciu podobných obrázkov. Spolieha sa na inteligentné vyhľadávanie",
"exclusion_pattern_description": "Vylučovacie vzory Vám umožňujú ignorovať súbory a priečinky pri skenovaní Vašej knižnice. Toto je užitočné, ak máte priečinky obsahujúce súbory, ktoré nechcete importovať, napríklad RAW súbory.", "exclusion_pattern_description": "Vylučovacie vzory Vám umožňujú ignorovať súbory a priečinky pri skenovaní Vašej knižnice. Toto je užitočné, ak máte priečinky obsahujúce súbory, ktoré nechcete importovať, napríklad RAW súbory.",
"external_library_management": "Správa Externej Knižnice", "external_library_management": "Spravovanie externej knižnice",
"face_detection": "Detekcia tvárí", "face_detection": "Detekcia tvárí",
"face_detection_description": "Rozpoznajte tváre v položkách pomocou strojového učenia. V prípade videí sa berie do úvahy len náhľad. „Obnoviť“ (znovu) spracuje všetky položky. „Resetovať“ dodatočne vymaže všetky aktuálne údaje o tvárach. „Chýbajúce“ zaradí do poradia médiá, ktoré ešte neboli spracované. Zistené tváre sa po dokončení rozpoznávania tvárí zaradia do poradia na rozpoznávanie tvárí, pričom sa zoskupia do existujúcich alebo nových osôb.", "face_detection_description": "Rozpoznajte tváre v položkách pomocou strojového učenia. V prípade videí sa berie do úvahy len náhľad. „Aktualizovať“ (znovu) spracuje všetky položky. „Obnoviť“ dodatočne vymaže všetky aktuálne údaje o tvárach. „Chýbajúce“ zaradí do poradia médiá, ktoré ešte neboli spracované. Zistené tváre sa po dokončení rozpoznávania tvárí zaradia do poradia na rozpoznávanie tvárí, pričom sa zoskupia do existujúcich alebo nových osôb.",
"facial_recognition_job_description": "Zoskupte rozpoznané tváre do osôb. Tento krok sa vykoná po dokončení rozpoznávania tvárí. „Resetovať“ (znovu) zoskupí všetky tváre. „Chýbajúce“ zaradí tváre, ktoré nemajú pridelenú osobu.", "facial_recognition_job_description": "Zoskupte rozpoznané tváre do osôb. Tento krok sa vykoná po dokončení rozpoznávania tvárí. „Obnoviť“ (znovu) zoskupí všetky tváre. „Chýbajúce“ zaradí tváre, ktoré nemajú pridelenú osobu.",
"failed_job_command": "Príkaz {command} zlyhal pre úlohu: {job}", "failed_job_command": "Príkaz {command} zlyhal pre úlohu: {job}",
"force_delete_user_warning": "VAROVANIE: Toto okamžite odstráni používateľa a všetky položky. Tento krok nie je možné vrátiť späť a súbory nebude možné obnoviť.", "force_delete_user_warning": "VAROVANIE: Toto okamžite odstráni používateľa a všetky položky. Tento krok nie je možné vrátiť späť a súbory nebude možné obnoviť.",
"image_format": "Formát", "image_format": "Formát",
@@ -94,7 +94,7 @@
"job_not_concurrency_safe": "Táto úloha nie je bezpečná pre súbežné spracovanie.", "job_not_concurrency_safe": "Táto úloha nie je bezpečná pre súbežné spracovanie.",
"job_settings": "Úlohy", "job_settings": "Úlohy",
"job_settings_description": "Spravovať súbežnosť úloh", "job_settings_description": "Spravovať súbežnosť úloh",
"job_status": "Stav Úloh", "job_status": "Stav úloh",
"jobs_delayed": "{jobCount, plural, one {# oneskorený} few {# oneskorené} other {# oneskorených}}", "jobs_delayed": "{jobCount, plural, one {# oneskorený} few {# oneskorené} other {# oneskorených}}",
"jobs_failed": "{jobCount, plural, one {# neúspešný} few {# neúspešné} other {# neúspešných}}", "jobs_failed": "{jobCount, plural, one {# neúspešný} few {# neúspešné} other {# neúspešných}}",
"library_created": "Vytvorená knižnica: {library}", "library_created": "Vytvorená knižnica: {library}",
@@ -141,15 +141,15 @@
"machine_learning_smart_search_enabled": "Povoliť inteligentné vyhľadávanie", "machine_learning_smart_search_enabled": "Povoliť inteligentné vyhľadávanie",
"machine_learning_smart_search_enabled_description": "Ak je vypnuté, obrázky nebudú spracované pre inteligentné vyhľadávanie.", "machine_learning_smart_search_enabled_description": "Ak je vypnuté, obrázky nebudú spracované pre inteligentné vyhľadávanie.",
"machine_learning_url_description": "URL adresa servera strojového učenia. Ak je zadaných viacero adries URL, každý server bude testovaný postupne, kým jeden z nich neodpovie úspešne, v poradí od prvého po posledný. Servery, ktoré neodpovedajú, budú dočasne ignorované, kým nebudú opäť online.", "machine_learning_url_description": "URL adresa servera strojového učenia. Ak je zadaných viacero adries URL, každý server bude testovaný postupne, kým jeden z nich neodpovie úspešne, v poradí od prvého po posledný. Servery, ktoré neodpovedajú, budú dočasne ignorované, kým nebudú opäť online.",
"manage_concurrency": "Správa súbežnosti", "manage_concurrency": "Spravovať súbežnosť",
"manage_log_settings": "Spravovať nastavenia ukladania záznamov", "manage_log_settings": "Spravovať nastavenia ukladania záznamov",
"map_dark_style": "Tmavý štýl", "map_dark_style": "Tmavý štýl",
"map_enable_description": "Povoliť funkcie mapy", "map_enable_description": "Povoliť funkcie mapy",
"map_gps_settings": "Mapa a nastavenia GPS", "map_gps_settings": "Mapa a nastavenia GPS",
"map_gps_settings_description": "Spravujte nastavenia mapy a GPS (reverzné geokódovanie)", "map_gps_settings_description": "Spravovať nastavenia mapy a GPS (reverzné geokódovanie)",
"map_implications": "Táto funkčnosť sa spolieha na externý servis spracovania mapových dlaždíc (tiles.immich.cloud)", "map_implications": "Táto funkčnosť sa spolieha na externý servis spracovania mapových dlaždíc (tiles.immich.cloud)",
"map_light_style": "Svetlý štýl", "map_light_style": "Svetlý štýl",
"map_manage_reverse_geocoding_settings": "Správa nastavení <link>Reverzného geokódovania</link>", "map_manage_reverse_geocoding_settings": "Spravovať nastavenia <link>reverzného geokódovania</link>",
"map_reverse_geocoding": "Reverzné Geokódovanie", "map_reverse_geocoding": "Reverzné Geokódovanie",
"map_reverse_geocoding_enable_description": "Povoliť reverzné geokódovanie", "map_reverse_geocoding_enable_description": "Povoliť reverzné geokódovanie",
"map_reverse_geocoding_settings": "Reverzné geokódovanie", "map_reverse_geocoding_settings": "Reverzné geokódovanie",
@@ -214,7 +214,7 @@
"oauth_role_claim_description": "Automaticky udeliť prístup správcu na základe prítomnosti tejto požiadavky. Požiadavka môže mať príznak „user“ alebo „admin“.", "oauth_role_claim_description": "Automaticky udeliť prístup správcu na základe prítomnosti tejto požiadavky. Požiadavka môže mať príznak „user“ alebo „admin“.",
"oauth_settings": "OAuth", "oauth_settings": "OAuth",
"oauth_settings_description": "Spravovať nastavenia prihlásenia OAuth", "oauth_settings_description": "Spravovať nastavenia prihlásenia OAuth",
"oauth_settings_more_details": "Pre viac informácii o tejto funkcii, prejdite na <link>docs</link>.", "oauth_settings_more_details": "Pre viac informácii o tejto funkcii, prejdite na <link>dokumentáciu</link>.",
"oauth_storage_label_claim": "Nárokovať Štítok úložiska", "oauth_storage_label_claim": "Nárokovať Štítok úložiska",
"oauth_storage_label_claim_description": "Automaticky nastaviť štítok úložiska používateľa na hodnotu tohto nároku.", "oauth_storage_label_claim_description": "Automaticky nastaviť štítok úložiska používateľa na hodnotu tohto nároku.",
"oauth_storage_quota_claim": "Deklarácia kvóty úložiska", "oauth_storage_quota_claim": "Deklarácia kvóty úložiska",
@@ -234,7 +234,7 @@
"registration_description": "Keďže ste prvým používateľom v systéme, budú vám pridelené správcovské práva na vykonávanie všetkých úloh a vrátane tvorby nových používateľov.", "registration_description": "Keďže ste prvým používateľom v systéme, budú vám pridelené správcovské práva na vykonávanie všetkých úloh a vrátane tvorby nových používateľov.",
"require_password_change_on_login": "Vyžadovať od používateľa zmenu hesla pri prvom prihlásení", "require_password_change_on_login": "Vyžadovať od používateľa zmenu hesla pri prvom prihlásení",
"reset_settings_to_default": "Obnoviť pôvodné nastavenia", "reset_settings_to_default": "Obnoviť pôvodné nastavenia",
"reset_settings_to_recent_saved": "Obnov naposledy uložené nastavenia", "reset_settings_to_recent_saved": "Nastavenia boli obnovené na posled uložené nastavenia",
"scanning_library": "Knižnica sa skenuje", "scanning_library": "Knižnica sa skenuje",
"search_jobs": "Vyhľadať úlohy…", "search_jobs": "Vyhľadať úlohy…",
"send_welcome_email": "Odoslať uvítací e-mail", "send_welcome_email": "Odoslať uvítací e-mail",
@@ -259,7 +259,7 @@
"storage_template_migration_description": "Použite aktuálnu <link>{template}</link> na predtým nahrané médiá", "storage_template_migration_description": "Použite aktuálnu <link>{template}</link> na predtým nahrané médiá",
"storage_template_migration_info": "Šablóna úložiska skonvertuje všetky prípony na malé písmená. Zmeny šablón sa budú vzťahovať iba na nové diela. Ak chcete šablónu spätne použiť na predtým nahrané médiá, spustite <link>{job}</link>.", "storage_template_migration_info": "Šablóna úložiska skonvertuje všetky prípony na malé písmená. Zmeny šablón sa budú vzťahovať iba na nové diela. Ak chcete šablónu spätne použiť na predtým nahrané médiá, spustite <link>{job}</link>.",
"storage_template_migration_job": "Úloha migrácie šablóny úložiska", "storage_template_migration_job": "Úloha migrácie šablóny úložiska",
"storage_template_more_details": "Ďalšie podrobnosti o tejto funkcii nájdete v <template-link>Šablóna úložiska</template-link> a jej <implications-link>sledky</implications-link>", "storage_template_more_details": "Podrobnejšie informácie o tejto funkcii nájdete v časti <template-link>šablóna úložiska</template-link> a jej <implications-link>sledky</implications-link>",
"storage_template_onboarding_description_v2": "Ak je táto funkcia zapnutá, automaticky usporiada súbory na základe šablóny definovanej používateľom. Ďalšie informácie nájdete v <link>dokumentácii</link>.", "storage_template_onboarding_description_v2": "Ak je táto funkcia zapnutá, automaticky usporiada súbory na základe šablóny definovanej používateľom. Ďalšie informácie nájdete v <link>dokumentácii</link>.",
"storage_template_path_length": "Približný limit dĺžky cesty: <b>{length, number}</b>/{limit, number}", "storage_template_path_length": "Približný limit dĺžky cesty: <b>{length, number}</b>/{limit, number}",
"storage_template_settings": "Šablóna úložiska", "storage_template_settings": "Šablóna úložiska",
@@ -278,9 +278,9 @@
"template_settings_description": "Spravovanie vlastných šablón upozornení", "template_settings_description": "Spravovanie vlastných šablón upozornení",
"theme_custom_css_settings": "Vlastné CSS", "theme_custom_css_settings": "Vlastné CSS",
"theme_custom_css_settings_description": "CSS štýly umožňujú prispôsobiť dizajn Immich.", "theme_custom_css_settings_description": "CSS štýly umožňujú prispôsobiť dizajn Immich.",
"theme_settings": "Motívy", "theme_settings": "Nastavenia témy",
"theme_settings_description": "Spravovať prispôsobenie webového rozhrania Immich", "theme_settings_description": "Spravovať prispôsobenie webového rozhrania Immich",
"thumbnail_generation_job": "Generovať Miniatúry", "thumbnail_generation_job": "Generovať miniatúry",
"thumbnail_generation_job_description": "Generujte veľké, malé a rozmazané miniatúry pre každú položku, ako aj miniatúry pre každú osobu", "thumbnail_generation_job_description": "Generujte veľké, malé a rozmazané miniatúry pre každú položku, ako aj miniatúry pre každú osobu",
"transcoding_acceleration_api": "API pre akceleráciu", "transcoding_acceleration_api": "API pre akceleráciu",
"transcoding_acceleration_api_description": "Rozhranie API, ktoré bude spolupracovať s vaším zariadením s cieľom urýchliť prekódovanie. Toto nastavenie je „najlepšie úsilie“: pri zlyhaní sa vráti k softvérovému prekódovaniu. VP9 môže alebo nemusí fungovať v závislosti od vášho hardvéru.", "transcoding_acceleration_api_description": "Rozhranie API, ktoré bude spolupracovať s vaším zariadením s cieľom urýchliť prekódovanie. Toto nastavenie je „najlepšie úsilie“: pri zlyhaní sa vráti k softvérovému prekódovaniu. VP9 môže alebo nemusí fungovať v závislosti od vášho hardvéru.",
@@ -300,7 +300,7 @@
"transcoding_bitrate_description": "Videá presahujúce maximálnu bitovú rýchlosť alebo videá, ktoré nie sú v akceptovanom formáte", "transcoding_bitrate_description": "Videá presahujúce maximálnu bitovú rýchlosť alebo videá, ktoré nie sú v akceptovanom formáte",
"transcoding_codecs_learn_more": "Ak sa chcete dozvedieť viac o tu použitej terminológii, pozrite si dokumentáciu FFmpeg pre <h264-link>kodek H.264</h264-link>, <hevc-link>kodek HEVC</hevc-link> a <vp9-link>VP9 kodek</vp9-link>.", "transcoding_codecs_learn_more": "Ak sa chcete dozvedieť viac o tu použitej terminológii, pozrite si dokumentáciu FFmpeg pre <h264-link>kodek H.264</h264-link>, <hevc-link>kodek HEVC</hevc-link> a <vp9-link>VP9 kodek</vp9-link>.",
"transcoding_constant_quality_mode": "Režim konštantnej kvality", "transcoding_constant_quality_mode": "Režim konštantnej kvality",
"transcoding_constant_quality_mode_description": "ICQ je lepšie ako CQP, ale niektoré zariadenia na hardvérovú akceleráciu tento režim nepodporujú. Nastavenie tejto možnosti uprednostní špecifikovaný režim pri použití kódovania založeného na kvalite. Ignorované spoločnosťou NVENC, pretože nepodporuje ICQ.", "transcoding_constant_quality_mode_description": "ICQ je lepšie ako CQP, ale niektoré zariadenia na hardvérovú akceleráciu tento režim nepodporujú. Nastavenie tejto možnosti uprednostní špecifikovaný režim pri použití kódovania založeného na kvalite. Ignorované funkciou NVENC, pretože nepodporuje ICQ.",
"transcoding_constant_rate_factor": "Faktor konštantnej rýchlosti (-crf)", "transcoding_constant_rate_factor": "Faktor konštantnej rýchlosti (-crf)",
"transcoding_constant_rate_factor_description": "Úroveň kvality videa. Typické hodnoty sú 23 pre H.264, 28 pre HEVC, 31 pre VP9 a 35 pre AV1. Nižšie je lepšie, ale vytvára väčšie súbory.", "transcoding_constant_rate_factor_description": "Úroveň kvality videa. Typické hodnoty sú 23 pre H.264, 28 pre HEVC, 31 pre VP9 a 35 pre AV1. Nižšie je lepšie, ale vytvára väčšie súbory.",
"transcoding_disabled_description": "Neprekódovať žiadne videá, na niektorých klientoch môže prerušiť prehrávanie", "transcoding_disabled_description": "Neprekódovať žiadne videá, na niektorých klientoch môže prerušiť prehrávanie",
@@ -321,13 +321,13 @@
"transcoding_policy_description": "Nastavte, kedy bude video prekódované", "transcoding_policy_description": "Nastavte, kedy bude video prekódované",
"transcoding_preferred_hardware_device": "Uprednostňované hardvérové zariadenie", "transcoding_preferred_hardware_device": "Uprednostňované hardvérové zariadenie",
"transcoding_preferred_hardware_device_description": "Platí len pre VAAPI a QSV. Nastavuje uzol dri, ktorý sa používa na hardvérové prekódovanie.", "transcoding_preferred_hardware_device_description": "Platí len pre VAAPI a QSV. Nastavuje uzol dri, ktorý sa používa na hardvérové prekódovanie.",
"transcoding_preset_preset": "Prednastavenie (-preset)", "transcoding_preset_preset": "Predvoľba (-preset)",
"transcoding_preset_preset_description": "Rýchlosť kompresie. Pomalšie predvoľby vytvárajú menšie súbory a zvyšujú kvalitu, keď sa zameriavajú na určitý dátový tok. VP9 ignoruje rýchlosti vyššie ako „rýchlejšie“.", "transcoding_preset_preset_description": "Rýchlosť kompresie. Pomalšie predvoľby vytvárajú menšie súbory a zvyšujú kvalitu, keď sa zameriavajú na určitý dátový tok. VP9 ignoruje rýchlosti vyššie ako „rýchlejšie“.",
"transcoding_reference_frames": "Referenčné snímky", "transcoding_reference_frames": "Referenčné snímky",
"transcoding_reference_frames_description": "Počet snímok, na ktoré sa má odkazovať pri kompresii daného snímku. Vyššie hodnoty zvyšujú účinnosť kompresie, ale spomaľujú kódovanie. Hodnota 0 sa nastavuje automaticky.", "transcoding_reference_frames_description": "Počet snímok, na ktoré sa má odkazovať pri kompresii daného snímku. Vyššie hodnoty zvyšujú účinnosť kompresie, ale spomaľujú kódovanie. Hodnota 0 sa nastavuje automaticky.",
"transcoding_required_description": "Iba videá, ktoré nie sú v prijatom formáte", "transcoding_required_description": "Iba videá, ktoré nie sú v prijatom formáte",
"transcoding_settings": "Nastavenia prekódovania videa", "transcoding_settings": "Nastavenia prekódovania videa",
"transcoding_settings_description": "Spravujte, ktoré videá sa majú prekódovať a ako ich spracovať", "transcoding_settings_description": "Spravovať, ktoré videá sa majú prekódovať a ako sa majú spracovať",
"transcoding_target_resolution": "Cieľové rozlíšenie", "transcoding_target_resolution": "Cieľové rozlíšenie",
"transcoding_target_resolution_description": "Vyššie rozlíšenia môžu zachovať viac detailov, ale ich kódovanie trvá dlhšie, majú väčšiu veľkosť súborov a môžu znížiť odozvu aplikácie.", "transcoding_target_resolution_description": "Vyššie rozlíšenia môžu zachovať viac detailov, ale ich kódovanie trvá dlhšie, majú väčšiu veľkosť súborov a môžu znížiť odozvu aplikácie.",
"transcoding_temporal_aq": "Časové AQ", "transcoding_temporal_aq": "Časové AQ",
@@ -349,13 +349,13 @@
"trash_settings_description": "Spravovať nastavenia koša", "trash_settings_description": "Spravovať nastavenia koša",
"user_cleanup_job": "Premazanie používateľov", "user_cleanup_job": "Premazanie používateľov",
"user_delete_delay": "Konto <b>{user}</b> a jeho médiá budú podľa plánu natrvalo vymazané za {delay, plural, one {# deň} few {# dni} other {# dní}}.", "user_delete_delay": "Konto <b>{user}</b> a jeho médiá budú podľa plánu natrvalo vymazané za {delay, plural, one {# deň} few {# dni} other {# dní}}.",
"user_delete_delay_settings": "Odstrániť oneskorenie", "user_delete_delay_settings": "Oneskorenie vymazania",
"user_delete_delay_settings_description": "Počet dní po odstránení na trvalé vymazanie účtu a médií používateľa. Úloha odstraňovania používateľov sa spúšťa o polnoci, aby sa skontrolovali používatelia, ktorí sú pripravení na odstránenie. Zmeny tohto nastavenia sa vyhodnotia pri ďalšom spustení.", "user_delete_delay_settings_description": "Počet dní, po ktorých sa po odstránení používateľa natrvalo odstráni jeho účet a položky. Úloha odstraňovania používateľov sa spúšťa o polnoci, aby sa skontrolovali používatelia, ktorí sú pripravení na odstránenie. Zmeny tohto nastavenia sa vyhodnotia pri ďalšom spustení.",
"user_delete_immediately": "Konto a médiá používateľa <b>{user}</b> budú zaradené do poradia na trvalé vymazanie <b>okamžite</b>.", "user_delete_immediately": "Konto a médiá používateľa <b>{user}</b> budú zaradené do poradia na trvalé vymazanie <b>okamžite</b>.",
"user_delete_immediately_checkbox": "Používateľ a médiá budú zaradení do frontu na okamžité vymazanie", "user_delete_immediately_checkbox": "Používateľ a médiá budú zaradení do frontu na okamžité vymazanie",
"user_details": "Podrobnosti o používateľovi", "user_details": "Podrobnosti o používateľovi",
"user_management": "Správa používateľov", "user_management": "Spravovanie používateľov",
"user_password_has_been_reset": "Heslo používateľa bolo resetované:", "user_password_has_been_reset": "Heslo používateľa bolo obnovené:",
"user_password_reset_description": "Poskytnite používateľovi dočasné heslo a informujte ho, že si ho bude musieť zmeniť pri ďalšom prihlásení.", "user_password_reset_description": "Poskytnite používateľovi dočasné heslo a informujte ho, že si ho bude musieť zmeniť pri ďalšom prihlásení.",
"user_restore_description": "<b>{user}</b> bude účet obnovený.", "user_restore_description": "<b>{user}</b> bude účet obnovený.",
"user_restore_scheduled_removal": "Obnoviť používateľa - plánované odstránenie na {date, date, long}", "user_restore_scheduled_removal": "Obnoviť používateľa - plánované odstránenie na {date, date, long}",
@@ -393,7 +393,7 @@
"age_year_months": "Vek 1 rok, {months, plural, one {# month} other {# months}}", "age_year_months": "Vek 1 rok, {months, plural, one {# month} other {# months}}",
"age_years": "{years, plural, other {Vek #}}", "age_years": "{years, plural, other {Vek #}}",
"album_added": "Album bol pridaný", "album_added": "Album bol pridaný",
"album_added_notification_setting_description": "Obdržať upozornenie emailom, keď ste prida do zdieľaného albumu", "album_added_notification_setting_description": "Obdržať upozornenie emailom, keď vás prida do zdieľaného albumu",
"album_cover_updated": "Obal albumu aktualizovaný", "album_cover_updated": "Obal albumu aktualizovaný",
"album_delete_confirmation": "Ste si istý, že chcete odstrániť album {album}?", "album_delete_confirmation": "Ste si istý, že chcete odstrániť album {album}?",
"album_delete_confirmation_description": "Ak je tento album zdieľaný, ostatní používatelia k nemu už nebudú mať prístup.", "album_delete_confirmation_description": "Ak je tento album zdieľaný, ostatní používatelia k nemu už nebudú mať prístup.",
@@ -573,6 +573,8 @@
"backup_options_page_title": "Možnosti zálohovania", "backup_options_page_title": "Možnosti zálohovania",
"backup_setting_subtitle": "Spravovať nastavenia odosielania na pozadí a v popredí", "backup_setting_subtitle": "Spravovať nastavenia odosielania na pozadí a v popredí",
"backward": "Dozadu", "backward": "Dozadu",
"beta_sync": "Stav synchronizácie verzie Beta",
"beta_sync_subtitle": "Spravovať nový systém synchronizácie",
"biometric_auth_enabled": "Biometrické overovanie je povolené", "biometric_auth_enabled": "Biometrické overovanie je povolené",
"biometric_locked_out": "Ste vymknutí z biometrického overovania", "biometric_locked_out": "Ste vymknutí z biometrického overovania",
"biometric_no_options": "Nie sú k dispozícii žiadne biometrické možnosti", "biometric_no_options": "Nie sú k dispozícii žiadne biometrické možnosti",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Vymazať vyrovnávaciu pamäť", "cache_settings_clear_cache_button": "Vymazať vyrovnávaciu pamäť",
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávaciu pamäť aplikácie. To výrazne ovplyvní výkon aplikácie, kým sa vyrovnávacia pamäť neobnoví.", "cache_settings_clear_cache_button_title": "Vymaže vyrovnávaciu pamäť aplikácie. To výrazne ovplyvní výkon aplikácie, kým sa vyrovnávacia pamäť neobnoví.",
"cache_settings_duplicated_assets_clear_button": "VYČISTIŤ", "cache_settings_duplicated_assets_clear_button": "VYČISTIŤ",
"cache_settings_duplicated_assets_subtitle": "Fotky a videá ktoré sú na čiernej listine zvolené aplikáciou", "cache_settings_duplicated_assets_subtitle": "Fotografie a videá, ktoré aplikácia ignoruje podľa zoznamu",
"cache_settings_duplicated_assets_title": "Duplicitné položky ({count})", "cache_settings_duplicated_assets_title": "Duplicitné položky ({count})",
"cache_settings_statistics_album": "Knižnica náhľadov", "cache_settings_statistics_album": "Knižnica náhľadov",
"cache_settings_statistics_full": "Kompletné fotografie", "cache_settings_statistics_full": "Kompletné fotografie",
@@ -628,7 +630,7 @@
"change_password_form_password_mismatch": "Heslá sa nezhodujú", "change_password_form_password_mismatch": "Heslá sa nezhodujú",
"change_password_form_reenter_new_password": "Znova zadajte nové heslo", "change_password_form_reenter_new_password": "Znova zadajte nové heslo",
"change_pin_code": "Zmeniť PIN kód", "change_pin_code": "Zmeniť PIN kód",
"change_your_password": "Zmeňte si heslo", "change_your_password": "Zmeniť heslo",
"changed_visibility_successfully": "Viditeľnosť bola úspešne zmenená", "changed_visibility_successfully": "Viditeľnosť bola úspešne zmenená",
"check_corrupt_asset_backup": "Skontrolovať, či nie sú poškodené zálohy položiek", "check_corrupt_asset_backup": "Skontrolovať, či nie sú poškodené zálohy položiek",
"check_corrupt_asset_backup_button": "Vykonať kontrolu", "check_corrupt_asset_backup_button": "Vykonať kontrolu",
@@ -723,7 +725,7 @@
"custom_locale_description": "Formátovanie dátumov a čísel podľa jazyka a regiónu", "custom_locale_description": "Formátovanie dátumov a čísel podľa jazyka a regiónu",
"daily_title_text_date": "EEEE, d. MMMM", "daily_title_text_date": "EEEE, d. MMMM",
"daily_title_text_date_year": "EEEE, d. MMMM y", "daily_title_text_date_year": "EEEE, d. MMMM y",
"dark": "Tmavý", "dark": "Tmavá",
"dark_theme": "Prepnúť tmavú tému", "dark_theme": "Prepnúť tmavú tému",
"date_after": "Dátum po", "date_after": "Dátum po",
"date_and_time": "Dátum a Čas", "date_and_time": "Dátum a Čas",
@@ -949,7 +951,7 @@
"unable_to_remove_library": "Nie je možné odstrániť knižnicu", "unable_to_remove_library": "Nie je možné odstrániť knižnicu",
"unable_to_remove_partner": "Nie je možné odstrániť partnera", "unable_to_remove_partner": "Nie je možné odstrániť partnera",
"unable_to_remove_reaction": "Nie je možné odstrániť reakciu", "unable_to_remove_reaction": "Nie je možné odstrániť reakciu",
"unable_to_reset_password": "Nie je možné resetovať heslo", "unable_to_reset_password": "Nie je možné obnoviť heslo",
"unable_to_reset_pin_code": "Nie je možné obnoviť PIN kód", "unable_to_reset_pin_code": "Nie je možné obnoviť PIN kód",
"unable_to_resolve_duplicate": "Nie je možné vyriešiť duplikát", "unable_to_resolve_duplicate": "Nie je možné vyriešiť duplikát",
"unable_to_restore_assets": "Nie je možné obnoviť položky", "unable_to_restore_assets": "Nie je možné obnoviť položky",
@@ -987,7 +989,7 @@
"exif_bottom_sheet_person_age_months": "Vek {months} mesiacov", "exif_bottom_sheet_person_age_months": "Vek {months} mesiacov",
"exif_bottom_sheet_person_age_year_months": "Vek 1 rok, {months} mesiacov", "exif_bottom_sheet_person_age_year_months": "Vek 1 rok, {months} mesiacov",
"exif_bottom_sheet_person_age_years": "Vek {years}", "exif_bottom_sheet_person_age_years": "Vek {years}",
"exit_slideshow": "Opustiť Slideshow", "exit_slideshow": "Opustiť prezentáciu",
"expand_all": "Rozbaliť všetko", "expand_all": "Rozbaliť všetko",
"experimental_settings_new_asset_list_subtitle": "Prebiehajúca práca", "experimental_settings_new_asset_list_subtitle": "Prebiehajúca práca",
"experimental_settings_new_asset_list_title": "Povolenie experimentálnej mriežky fotografií", "experimental_settings_new_asset_list_title": "Povolenie experimentálnej mriežky fotografií",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Povoliť hmatovú odozvu", "haptic_feedback_switch": "Povoliť hmatovú odozvu",
"haptic_feedback_title": "Hmatová odozva", "haptic_feedback_title": "Hmatová odozva",
"has_quota": "Má kvótu", "has_quota": "Má kvótu",
"hash_asset": "Hashovať položku",
"hashed_assets": "Hashované položky",
"hashing": "Hashovanie",
"header_settings_add_header_tip": "Pridať hlavičku", "header_settings_add_header_tip": "Pridať hlavičku",
"header_settings_field_validator_msg": "Hodnota nemôže byť prázdna", "header_settings_field_validator_msg": "Hodnota nemôže byť prázdna",
"header_settings_header_name_input": "Názov hlavičky", "header_settings_header_name_input": "Názov hlavičky",
@@ -1083,6 +1088,7 @@
"host": "Hostiteľ", "host": "Hostiteľ",
"hour": "Hodina", "hour": "Hodina",
"id": "ID", "id": "ID",
"idle": "Nečinné",
"ignore_icloud_photos": "Ignorovať fotky v službe iCloud", "ignore_icloud_photos": "Ignorovať fotky v službe iCloud",
"ignore_icloud_photos_description": "Fotografie uložené v službe iCloud sa nebudú odosielať na server Immich", "ignore_icloud_photos_description": "Fotografie uložené v službe iCloud sa nebudú odosielať na server Immich",
"image": "Obrázok", "image": "Obrázok",
@@ -1139,7 +1145,7 @@
"language_no_results_subtitle": "Skúste upraviť hľadaný výraz", "language_no_results_subtitle": "Skúste upraviť hľadaný výraz",
"language_no_results_title": "Neboli nájdené žiadne jazyky", "language_no_results_title": "Neboli nájdené žiadne jazyky",
"language_search_hint": "Vyhľadať jazyky...", "language_search_hint": "Vyhľadať jazyky...",
"language_setting_description": "Vyberte preferovaný jazyk", "language_setting_description": "Vyberte požadovaný jazyk",
"last_seen": "Naposledy videné", "last_seen": "Naposledy videné",
"latest_version": "Najnovšia verzia", "latest_version": "Najnovšia verzia",
"latitude": "Zemepisná šírka", "latitude": "Zemepisná šírka",
@@ -1156,7 +1162,7 @@
"library_page_sort_last_modified": "Naposledy upravené", "library_page_sort_last_modified": "Naposledy upravené",
"library_page_sort_title": "Podľa názvu albumu", "library_page_sort_title": "Podľa názvu albumu",
"licenses": "Licencie", "licenses": "Licencie",
"light": "Svetlý", "light": "Svetlá",
"like_deleted": "Like odstránený", "like_deleted": "Like odstránený",
"link_motion_video": "Pripojiť pohyblivé video", "link_motion_video": "Pripojiť pohyblivé video",
"link_options": "Možnosti odkazu", "link_options": "Možnosti odkazu",
@@ -1165,7 +1171,9 @@
"list": "Zoznam", "list": "Zoznam",
"loading": "Načítavanie", "loading": "Načítavanie",
"loading_search_results_failed": "Načítanie výsledkov hľadania sa nepodarilo", "loading_search_results_failed": "Načítanie výsledkov hľadania sa nepodarilo",
"local": "Lokálne",
"local_asset_cast_failed": "Nie je možné preniesť médium, ktoré nie je nahrané na serveri", "local_asset_cast_failed": "Nie je možné preniesť médium, ktoré nie je nahrané na serveri",
"local_assets": "Lokálne položky",
"local_network": "Miestna sieť", "local_network": "Miestna sieť",
"local_network_sheet_info": "Pri použití zadanej siete Wi-Fi sa aplikácia pripojí k serveru prostredníctvom tejto URL adresy", "local_network_sheet_info": "Pri použití zadanej siete Wi-Fi sa aplikácia pripojí k serveru prostredníctvom tejto URL adresy",
"location_permission": "Povolenie na určenie polohy", "location_permission": "Povolenie na určenie polohy",
@@ -1277,7 +1285,7 @@
"move_off_locked_folder": "Presunúť zo zamknutého priečinka", "move_off_locked_folder": "Presunúť zo zamknutého priečinka",
"move_to_lock_folder_action_prompt": "{count} pridaných do zamknutého priečinka", "move_to_lock_folder_action_prompt": "{count} pridaných do zamknutého priečinka",
"move_to_locked_folder": "Presunúť do zamknutého priečinka", "move_to_locked_folder": "Presunúť do zamknutého priečinka",
"move_to_locked_folder_confirmation": "Tieto fotografie a videá budú odstránené zo všetkých albumov a bude ich možné zobraziť len v zamknutom priečinku", "move_to_locked_folder_confirmation": "Tieto fotografie a videá budú odobrané zo všetkých albumov a bude ich možné zobraziť len v zamknutom priečinku",
"moved_to_archive": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do archívu", "moved_to_archive": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do archívu",
"moved_to_library": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do knižnice", "moved_to_library": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do knižnice",
"moved_to_trash": "Presunuté do koša", "moved_to_trash": "Presunuté do koša",
@@ -1322,6 +1330,7 @@
"no_results": "Žiadne výsledky", "no_results": "Žiadne výsledky",
"no_results_description": "Skúste synonymum alebo všeobecnejší výraz", "no_results_description": "Skúste synonymum alebo všeobecnejší výraz",
"no_shared_albums_message": "Vytvorí album na zdieľanie fotiek a videí s ľuďmi vo vašej sieti", "no_shared_albums_message": "Vytvorí album na zdieľanie fotiek a videí s ľuďmi vo vašej sieti",
"no_uploads_in_progress": "Žiadne prebiehajúce nahrávanie",
"not_in_any_album": "Nie je v žiadnom albume", "not_in_any_album": "Nie je v žiadnom albume",
"not_selected": "Nevybrané", "not_selected": "Nevybrané",
"note_apply_storage_label_to_previously_uploaded assets": "Poznámka: Ak chcete použiť Štítok úložiska na predtým nahrané médiá, spustite príkaz", "note_apply_storage_label_to_previously_uploaded assets": "Poznámka: Ak chcete použiť Štítok úložiska na predtým nahrané médiá, spustite príkaz",
@@ -1343,7 +1352,7 @@
"onboarding": "Na palube", "onboarding": "Na palube",
"onboarding_locale_description": "Vyberte požadovaný jazyk. Neskôr ho môžete zmeniť v nastaveniach.", "onboarding_locale_description": "Vyberte požadovaný jazyk. Neskôr ho môžete zmeniť v nastaveniach.",
"onboarding_privacy_description": "Nasledujúce (voliteľné) funkcie závisia na externých službách a kedykoľvek ich môžete vypnúť nastaveniach.", "onboarding_privacy_description": "Nasledujúce (voliteľné) funkcie závisia na externých službách a kedykoľvek ich môžete vypnúť nastaveniach.",
"onboarding_server_welcome_description": "Nastavme vašu inštanciu pomocou bežných nastavení.", "onboarding_server_welcome_description": "Poďme si nastav vašu inštanciu s niekoľkými bežnými nastaveniami.",
"onboarding_theme_description": "Vyberte farbu témy pre váš server. Môžete to aj neskôr zmeniť vo vašich nastaveniach.", "onboarding_theme_description": "Vyberte farbu témy pre váš server. Môžete to aj neskôr zmeniť vo vašich nastaveniach.",
"onboarding_user_welcome_description": "Začnime!", "onboarding_user_welcome_description": "Začnime!",
"onboarding_welcome_user": "Vitaj, {user}", "onboarding_welcome_user": "Vitaj, {user}",
@@ -1359,6 +1368,7 @@
"original": "originál", "original": "originál",
"other": "Ostatné", "other": "Ostatné",
"other_devices": "Ďalšie zariadenia", "other_devices": "Ďalšie zariadenia",
"other_entities": "Ostatné subjekty",
"other_variables": "Ostatné premenné", "other_variables": "Ostatné premenné",
"owned": "Vlastnené", "owned": "Vlastnené",
"owner": "Vlastník", "owner": "Vlastník",
@@ -1434,9 +1444,9 @@
"play_or_pause_video": "Pustí alebo pozastaví video", "play_or_pause_video": "Pustí alebo pozastaví video",
"please_auth_to_access": "Prosím, potvrďte overenie pre prístup", "please_auth_to_access": "Prosím, potvrďte overenie pre prístup",
"port": "Port", "port": "Port",
"preferences_settings_subtitle": "Spravujte predvoľby aplikácie", "preferences_settings_subtitle": "Spravovať predvoľby aplikácie",
"preferences_settings_title": "Predvoľby", "preferences_settings_title": "Predvoľby",
"preset": "Prednastavenie", "preset": "Predvoľba",
"preview": "Náhľad", "preview": "Náhľad",
"previous": "Predošlé", "previous": "Predošlé",
"previous_memory": "Predošlá spomienka", "previous_memory": "Predošlá spomienka",
@@ -1508,7 +1518,7 @@
"recently_added_page_title": "Nedávno pridané", "recently_added_page_title": "Nedávno pridané",
"recently_taken": "Nedávno nasnímané", "recently_taken": "Nedávno nasnímané",
"recently_taken_page_title": "Nedávno zhotovené", "recently_taken_page_title": "Nedávno zhotovené",
"refresh": "Obnoviť", "refresh": "Aktualizovať",
"refresh_encoded_videos": "Obnoviť enkódované videá", "refresh_encoded_videos": "Obnoviť enkódované videá",
"refresh_faces": "Obnoviť tváre", "refresh_faces": "Obnoviť tváre",
"refresh_metadata": "Obnoviť metadáta", "refresh_metadata": "Obnoviť metadáta",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Obnovovanie tvárí", "refreshing_faces": "Obnovovanie tvárí",
"refreshing_metadata": "Obnovovanie metadát", "refreshing_metadata": "Obnovovanie metadát",
"regenerating_thumbnails": "Pregenerovanie náhľadov", "regenerating_thumbnails": "Pregenerovanie náhľadov",
"remote": "Vzdialené",
"remote_assets": "Vzdialené položky",
"remove": "Odstrániť", "remove": "Odstrániť",
"remove_assets_album_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z albumu?", "remove_assets_album_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z albumu?",
"remove_assets_shared_link_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z tohoto zdieľaného odkazu?", "remove_assets_shared_link_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z tohoto zdieľaného odkazu?",
@@ -1529,8 +1541,8 @@
"remove_from_album_action_prompt": "{count} odstránené z albumu", "remove_from_album_action_prompt": "{count} odstránené z albumu",
"remove_from_favorites": "Odstrániť z obľúbených", "remove_from_favorites": "Odstrániť z obľúbených",
"remove_from_lock_folder_action_prompt": "{count} odobrané zo zamknutého priečinka", "remove_from_lock_folder_action_prompt": "{count} odobrané zo zamknutého priečinka",
"remove_from_locked_folder": "Odstrániť zo zamknutého priečinka", "remove_from_locked_folder": "Odobrať zo zamknutého priečinka",
"remove_from_locked_folder_confirmation": "Ste si istí, že chcete tieto fotografie a videá presunúť zo zamknutého priečinka? Budú viditeľné vo vašej knižnici.", "remove_from_locked_folder_confirmation": "Ste si istí, že chcete tieto fotografie a videá odobrať zo zamknutého priečinka? Budú viditeľné vo vašej knižnici.",
"remove_from_shared_link": "Odstrániť zo zdieľaného odkazu", "remove_from_shared_link": "Odstrániť zo zdieľaného odkazu",
"remove_memory": "Odstrániť spomienku", "remove_memory": "Odstrániť spomienku",
"remove_photo_from_memory": "Odstrániť fotografiu z tejto spomienky", "remove_photo_from_memory": "Odstrániť fotografiu z tejto spomienky",
@@ -1552,28 +1564,33 @@
"require_password": "Vyžadovať heslo", "require_password": "Vyžadovať heslo",
"require_user_to_change_password_on_first_login": "Vyžadovať zmenu hesla po prvom prihlásení", "require_user_to_change_password_on_first_login": "Vyžadovať zmenu hesla po prvom prihlásení",
"rescan": "Opätovné vyhľadávanie", "rescan": "Opätovné vyhľadávanie",
"reset": "Resetovať", "reset": "Obnoviť",
"reset_password": "Obnoviť heslo", "reset_password": "Obnoviť heslo",
"reset_people_visibility": "Resetovať viditeľnosť ľudí", "reset_people_visibility": "Obnoviť viditeľnosť ľudí",
"reset_pin_code": "Obnoviť PIN kód", "reset_pin_code": "Obnoviť PIN kód",
"reset_to_default": "Resetovať na predvolené", "reset_sqlite": "Obnoviť SQLite databázu",
"reset_sqlite_confirmation": "Ste si istí, že chcete obnoviť SQLite databázu? Na opätovnú synchronizáciu údajov sa budete musieť odhlásiť a znova prihlásiť",
"reset_sqlite_success": "Úspešné obnovenie databázy SQLite",
"reset_to_default": "Obnoviť na predvolené",
"resolve_duplicates": "Vyriešiť duplicity", "resolve_duplicates": "Vyriešiť duplicity",
"resolved_all_duplicates": "Vyriešené všetky duplicity", "resolved_all_duplicates": "Vyriešené všetky duplicity",
"restore": "Navrátiť", "restore": "Navrátiť",
"restore_all": "Navrátit všetko", "restore_all": "Navrátit všetko",
"restore_trash_action_prompt": "{count} obnovených z koša",
"restore_user": "Navrátiť používateľa", "restore_user": "Navrátiť používateľa",
"restored_asset": "Navrátené položky", "restored_asset": "Navrátené položky",
"resume": "Pokračovať", "resume": "Pokračovať",
"retry_upload": "Zopakovať nahrávanie", "retry_upload": "Zopakovať nahrávanie",
"review_duplicates": "Prezrieť duplikáty", "review_duplicates": "Preskúmať duplikáty",
"role": "Rola", "role": "Rola",
"role_editor": "Editor", "role_editor": "Editor",
"role_viewer": "Divák", "role_viewer": "Divák",
"running": "Spustené",
"save": "Uložiť", "save": "Uložiť",
"save_to_gallery": "Uložiť do galérie", "save_to_gallery": "Uložiť do galérie",
"saved_api_key": "Uložený API Kľúč", "saved_api_key": "Uložený API Kľúč",
"saved_profile": "Uložený profil", "saved_profile": "Uložený profil",
"saved_settings": "Uložené nastavenia", "saved_settings": "Nastavenia boli uložené",
"say_something": "Napíšte niečo", "say_something": "Napíšte niečo",
"scaffold_body_error_occurred": "Vyskytla sa chyba", "scaffold_body_error_occurred": "Vyskytla sa chyba",
"scan_all_libraries": "Preskenovať všetky knižnice", "scan_all_libraries": "Preskenovať všetky knižnice",
@@ -1585,7 +1602,7 @@
"search_by_context": "Hľadať s kontextom", "search_by_context": "Hľadať s kontextom",
"search_by_description": "Vyhľadávanie podľa popisu", "search_by_description": "Vyhľadávanie podľa popisu",
"search_by_description_example": "Pešia turistika v Sape", "search_by_description_example": "Pešia turistika v Sape",
"search_by_filename": "Hľadať s názvom alebo príponou súboru", "search_by_filename": "Hľadať podľa názvu alebo prípony súboru",
"search_by_filename_example": "napr. IMG_1234.JPG alebo PNG", "search_by_filename_example": "napr. IMG_1234.JPG alebo PNG",
"search_camera_make": "Hľadať značku fotoaparátu...", "search_camera_make": "Hľadať značku fotoaparátu...",
"search_camera_model": "Hľadať model fotoaparátu...", "search_camera_model": "Hľadať model fotoaparátu...",
@@ -1809,7 +1826,7 @@
"stacked_assets_count": "{count, plural, one {Zoskupená # položka} few {Zoskupené # položky} other {Zoskupených # položiek}}", "stacked_assets_count": "{count, plural, one {Zoskupená # položka} few {Zoskupené # položky} other {Zoskupených # položiek}}",
"stacktrace": "Výpis zásobníku", "stacktrace": "Výpis zásobníku",
"start": "Štart", "start": "Štart",
"start_date": "Začiatočný dátum", "start_date": "Počiatočný dátum",
"state": "Štát", "state": "Štát",
"status": "Stav", "status": "Stav",
"stop_casting": "Zastaviť prenos", "stop_casting": "Zastaviť prenos",
@@ -1822,6 +1839,7 @@
"storage_quota": "Úložný limit", "storage_quota": "Úložný limit",
"storage_usage": "Využitých {used} z {available}", "storage_usage": "Využitých {used} z {available}",
"submit": "Odoslať", "submit": "Odoslať",
"success": "Úspech",
"suggestions": "Návrhy", "suggestions": "Návrhy",
"sunrise_on_the_beach": "Východ slnka na pláži", "sunrise_on_the_beach": "Východ slnka na pláži",
"support": "Podpora", "support": "Podpora",
@@ -1831,9 +1849,11 @@
"sync": "Synchronizovať", "sync": "Synchronizovať",
"sync_albums": "Synchronizovať albumy", "sync_albums": "Synchronizovať albumy",
"sync_albums_manual_subtitle": "Synchronizujte všetky nahrané videá a fotografie s vybranými záložnými albumami", "sync_albums_manual_subtitle": "Synchronizujte všetky nahrané videá a fotografie s vybranými záložnými albumami",
"sync_local": "Synchronizovať lokálne",
"sync_remote": "Synchronizovať vzdialené",
"sync_upload_album_setting_subtitle": "Vytvárajte a nahrávajte svoje fotografie a videá do vybraných albumov na Immich", "sync_upload_album_setting_subtitle": "Vytvárajte a nahrávajte svoje fotografie a videá do vybraných albumov na Immich",
"tag": "Štítok", "tag": "Štítok",
"tag_assets": "Označiť položky", "tag_assets": "Pridať štítky",
"tag_created": "Vytvorený štítok: {tag}", "tag_created": "Vytvorený štítok: {tag}",
"tag_feature_description": "Prehliadanie fotiek a videá zoskupených podľa tematických štítkov", "tag_feature_description": "Prehliadanie fotiek a videá zoskupených podľa tematických štítkov",
"tag_not_found_question": "Neviete nájsť štítok? <link>Vytvorte nový štítok.</link>", "tag_not_found_question": "Neviete nájsť štítok? <link>Vytvorte nový štítok.</link>",
@@ -1841,6 +1861,7 @@
"tag_updated": "Upravený štítok: {tag}", "tag_updated": "Upravený štítok: {tag}",
"tagged_assets": "Štítok priradený {count, plural, one {# položke} other {# položkám}}", "tagged_assets": "Štítok priradený {count, plural, one {# položke} other {# položkám}}",
"tags": "Štítky", "tags": "Štítky",
"tap_to_run_job": "Ťuknutím na položku spustíte úlohu",
"template": "Šablóna", "template": "Šablóna",
"theme": "Téma", "theme": "Téma",
"theme_selection": "Výber témy", "theme_selection": "Výber témy",
@@ -1863,7 +1884,7 @@
"time_based_memories": "Časové spomienky", "time_based_memories": "Časové spomienky",
"timeline": "Časová os", "timeline": "Časová os",
"timezone": "Časové pásmo", "timezone": "Časové pásmo",
"to_archive": "Archív", "to_archive": "Archivovať",
"to_change_password": "Zmeniť heslo", "to_change_password": "Zmeniť heslo",
"to_favorite": "Obľúbiť", "to_favorite": "Obľúbiť",
"to_login": "Prihlásiť", "to_login": "Prihlásiť",
@@ -1898,7 +1919,7 @@
"unfavorite_action_prompt": "{count} odstránené z Obľúbených", "unfavorite_action_prompt": "{count} odstránené z Obľúbených",
"unhide_person": "Odkryť osobu", "unhide_person": "Odkryť osobu",
"unknown": "Neznáme", "unknown": "Neznáme",
"unknown_country": "Neznámy štát", "unknown_country": "Neznáma krajina",
"unknown_year": "Neznámy rok", "unknown_year": "Neznámy rok",
"unlimited": "Neobmedzené", "unlimited": "Neobmedzené",
"unlink_motion_video": "Odpojiť pohyblivé video", "unlink_motion_video": "Odpojiť pohyblivé video",
@@ -1986,7 +2007,7 @@
"viewer_stack_use_as_main_asset": "Použiť ako hlavnú fotku", "viewer_stack_use_as_main_asset": "Použiť ako hlavnú fotku",
"viewer_unstack": "Odskupiť", "viewer_unstack": "Odskupiť",
"visibility_changed": "Viditeľnosť zmenená pre {count, plural, one {# osobu} few {# osoby} other {# osôb}}", "visibility_changed": "Viditeľnosť zmenená pre {count, plural, one {# osobu} few {# osoby} other {# osôb}}",
"waiting": "Čaká", "waiting": "Čakajúce",
"warning": "Varovanie", "warning": "Varovanie",
"week": "Týždeň", "week": "Týždeň",
"welcome": "Vitajte", "welcome": "Vitajte",
@@ -1996,7 +2017,7 @@
"year": "Rok", "year": "Rok",
"years_ago": "pred {years, plural, one {# rokom} other {# rokmi}}", "years_ago": "pred {years, plural, one {# rokom} other {# rokmi}}",
"yes": "Áno", "yes": "Áno",
"you_dont_have_any_shared_links": "Nemáte žiadne zdielané linky", "you_dont_have_any_shared_links": "Nemáte žiadne zdielané odkazy",
"your_wifi_name": "Váš názov siete Wi-Fi", "your_wifi_name": "Váš názov siete Wi-Fi",
"zoom_image": "Priblížiť obrázok" "zoom_image": "Priblížiť obrázok"
} }
+23 -2
View File
@@ -573,6 +573,8 @@
"backup_options_page_title": "Možnosti varnostne kopije", "backup_options_page_title": "Možnosti varnostne kopije",
"backup_setting_subtitle": "Upravljaj nastavitve nalaganja v ozadju in ospredju", "backup_setting_subtitle": "Upravljaj nastavitve nalaganja v ozadju in ospredju",
"backward": "Nazaj", "backward": "Nazaj",
"beta_sync": "Stanje sinhronizacije beta različice",
"beta_sync_subtitle": "Upravljanje novega sistema sinhronizacije",
"biometric_auth_enabled": "Biometrična avtentikacija omogočena", "biometric_auth_enabled": "Biometrična avtentikacija omogočena",
"biometric_locked_out": "Biometrična avtentikacija vam je onemogočena", "biometric_locked_out": "Biometrična avtentikacija vam je onemogočena",
"biometric_no_options": "Biometrične možnosti niso na voljo", "biometric_no_options": "Biometrične možnosti niso na voljo",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "Počisti predpomnilnik", "cache_settings_clear_cache_button": "Počisti predpomnilnik",
"cache_settings_clear_cache_button_title": "Počisti predpomnilnik aplikacije. To bo znatno vplivalo na delovanje aplikacije, dokler se predpomnilnik ne obnovi.", "cache_settings_clear_cache_button_title": "Počisti predpomnilnik aplikacije. To bo znatno vplivalo na delovanje aplikacije, dokler se predpomnilnik ne obnovi.",
"cache_settings_duplicated_assets_clear_button": "POČISTI", "cache_settings_duplicated_assets_clear_button": "POČISTI",
"cache_settings_duplicated_assets_subtitle": "Fotografije in videoposnetki, ki jih je aplikacija uvrstila na črni seznam", "cache_settings_duplicated_assets_subtitle": "Fotografije in videoposnetki, ki so prezrti s strani aplikacije",
"cache_settings_duplicated_assets_title": "Podvojena sredstva ({count})", "cache_settings_duplicated_assets_title": "Podvojena sredstva ({count})",
"cache_settings_statistics_album": "Sličice knjižnice", "cache_settings_statistics_album": "Sličice knjižnice",
"cache_settings_statistics_full": "Izvirne slike", "cache_settings_statistics_full": "Izvirne slike",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "Uporabi haptičen odziv", "haptic_feedback_switch": "Uporabi haptičen odziv",
"haptic_feedback_title": "Haptičen odziv", "haptic_feedback_title": "Haptičen odziv",
"has_quota": "Ima kvoto", "has_quota": "Ima kvoto",
"hash_asset": "Zgoščeno sredstvo",
"hashed_assets": "Zgoščena sredstva",
"hashing": "Zgoščevanje",
"header_settings_add_header_tip": "Dodaj glavo", "header_settings_add_header_tip": "Dodaj glavo",
"header_settings_field_validator_msg": "Vrednost ne sme biti prazna", "header_settings_field_validator_msg": "Vrednost ne sme biti prazna",
"header_settings_header_name_input": "Ime glave", "header_settings_header_name_input": "Ime glave",
@@ -1083,6 +1088,7 @@
"host": "Gostitelj", "host": "Gostitelj",
"hour": "Ura", "hour": "Ura",
"id": "ID", "id": "ID",
"idle": "Nedejavnost",
"ignore_icloud_photos": "Ignoriraj fotografije iCloud", "ignore_icloud_photos": "Ignoriraj fotografije iCloud",
"ignore_icloud_photos_description": "Fotografije, shranjene v iCloud, ne bodo naložene na strežnik Immich", "ignore_icloud_photos_description": "Fotografije, shranjene v iCloud, ne bodo naložene na strežnik Immich",
"image": "Slika", "image": "Slika",
@@ -1165,7 +1171,9 @@
"list": "Seznam", "list": "Seznam",
"loading": "Nalaganje", "loading": "Nalaganje",
"loading_search_results_failed": "Nalaganje rezultatov iskanja ni uspelo", "loading_search_results_failed": "Nalaganje rezultatov iskanja ni uspelo",
"local": "Lokalno",
"local_asset_cast_failed": "Sredstva, ki niso naložena na strežnik, ni mogoče predvajati", "local_asset_cast_failed": "Sredstva, ki niso naložena na strežnik, ni mogoče predvajati",
"local_assets": "Lokalna sredstva",
"local_network": "Lokalno omrežje", "local_network": "Lokalno omrežje",
"local_network_sheet_info": "Aplikacija se bo povezala s strežnikom prek tega URL-ja, ko bo uporabljala navedeno omrežje Wi-Fi", "local_network_sheet_info": "Aplikacija se bo povezala s strežnikom prek tega URL-ja, ko bo uporabljala navedeno omrežje Wi-Fi",
"location_permission": "Dovoljenje za lokacijo", "location_permission": "Dovoljenje za lokacijo",
@@ -1322,6 +1330,7 @@
"no_results": "Brez rezultatov", "no_results": "Brez rezultatov",
"no_results_description": "Poskusite s sinonimom ali bolj splošno ključno besedo", "no_results_description": "Poskusite s sinonimom ali bolj splošno ključno besedo",
"no_shared_albums_message": "Ustvarite album za skupno rabo fotografij in videoposnetkov z osebami v vašem omrežju", "no_shared_albums_message": "Ustvarite album za skupno rabo fotografij in videoposnetkov z osebami v vašem omrežju",
"no_uploads_in_progress": "Ni nalaganj v teku",
"not_in_any_album": "Ni v nobenem albumu", "not_in_any_album": "Ni v nobenem albumu",
"not_selected": "Ni izbrano", "not_selected": "Ni izbrano",
"note_apply_storage_label_to_previously_uploaded assets": "Opomba: Če želite oznako za shranjevanje uporabiti za predhodno naložena sredstva, zaženite", "note_apply_storage_label_to_previously_uploaded assets": "Opomba: Če želite oznako za shranjevanje uporabiti za predhodno naložena sredstva, zaženite",
@@ -1359,6 +1368,7 @@
"original": "izvirnik", "original": "izvirnik",
"other": "drugo", "other": "drugo",
"other_devices": "Druge naprave", "other_devices": "Druge naprave",
"other_entities": "Drugi subjekti",
"other_variables": "Druge spremenljivke", "other_variables": "Druge spremenljivke",
"owned": "V lasti", "owned": "V lasti",
"owner": "Lastnik", "owner": "Lastnik",
@@ -1390,7 +1400,7 @@
"pause": "Premor", "pause": "Premor",
"pause_memories": "Zaustavi spomine", "pause_memories": "Zaustavi spomine",
"paused": "Zaustavljeno", "paused": "Zaustavljeno",
"pending": "V teku", "pending": "Čakanje",
"people": "Osebe", "people": "Osebe",
"people_edits_count": "{count, plural, one {Urejena # oseba} two {Urejeni # osebi} few {Urejene # osebe} other {Urejenih # oseb}}", "people_edits_count": "{count, plural, one {Urejena # oseba} two {Urejeni # osebi} few {Urejene # osebe} other {Urejenih # oseb}}",
"people_feature_description": "Brskanje po fotografijah in videoposnetkih, razvrščenih po osebah", "people_feature_description": "Brskanje po fotografijah in videoposnetkih, razvrščenih po osebah",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "Osveževanje obrazev", "refreshing_faces": "Osveževanje obrazev",
"refreshing_metadata": "Osveževanje metapodatkov", "refreshing_metadata": "Osveževanje metapodatkov",
"regenerating_thumbnails": "Obnavljanje sličic", "regenerating_thumbnails": "Obnavljanje sličic",
"remote": "Oddaljeno",
"remote_assets": "Oddaljena sredstva",
"remove": "Odstrani", "remove": "Odstrani",
"remove_assets_album_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz albuma?", "remove_assets_album_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz albuma?",
"remove_assets_shared_link_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz te skupne povezave?", "remove_assets_shared_link_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz te skupne povezave?",
@@ -1556,11 +1568,15 @@
"reset_password": "Ponastavi geslo", "reset_password": "Ponastavi geslo",
"reset_people_visibility": "Ponastavi vidnost ljudi", "reset_people_visibility": "Ponastavi vidnost ljudi",
"reset_pin_code": "Ponastavi PIN kodo", "reset_pin_code": "Ponastavi PIN kodo",
"reset_sqlite": "Ponastavi bazo podatkov SQLite",
"reset_sqlite_confirmation": "Ali ste prepričani, da želite ponastaviti bazo podatkov SQLite? Za ponovno sinhronizacijo podatkov se boste morali odjaviti in znova prijaviti",
"reset_sqlite_success": "Uspešno ponastavljena baza podatkov SQLite",
"reset_to_default": "Ponastavi na privzeto", "reset_to_default": "Ponastavi na privzeto",
"resolve_duplicates": "Razreši dvojnike", "resolve_duplicates": "Razreši dvojnike",
"resolved_all_duplicates": "Razrešeni vsi dvojniki", "resolved_all_duplicates": "Razrešeni vsi dvojniki",
"restore": "Obnovi", "restore": "Obnovi",
"restore_all": "Obnovi vse", "restore_all": "Obnovi vse",
"restore_trash_action_prompt": "{count} obnovljenih iz koša",
"restore_user": "Obnovi uporabnika", "restore_user": "Obnovi uporabnika",
"restored_asset": "Obnovljeno sredstvo", "restored_asset": "Obnovljeno sredstvo",
"resume": "Nadaljuj", "resume": "Nadaljuj",
@@ -1569,6 +1585,7 @@
"role": "Vloga", "role": "Vloga",
"role_editor": "Urejevalec", "role_editor": "Urejevalec",
"role_viewer": "Gledalec", "role_viewer": "Gledalec",
"running": "V teku",
"save": "Shrani", "save": "Shrani",
"save_to_gallery": "Shrani v galerijo", "save_to_gallery": "Shrani v galerijo",
"saved_api_key": "Shranjen API ključ", "saved_api_key": "Shranjen API ključ",
@@ -1822,6 +1839,7 @@
"storage_quota": "Kvota shranjevanja", "storage_quota": "Kvota shranjevanja",
"storage_usage": "uporabljeno {used} od {available}", "storage_usage": "uporabljeno {used} od {available}",
"submit": "Predloži", "submit": "Predloži",
"success": "Uspeh",
"suggestions": "Predlogi", "suggestions": "Predlogi",
"sunrise_on_the_beach": "Sončni vzhod na plaži", "sunrise_on_the_beach": "Sončni vzhod na plaži",
"support": "Podpora", "support": "Podpora",
@@ -1831,6 +1849,8 @@
"sync": "Sinhronizacija", "sync": "Sinhronizacija",
"sync_albums": "Sinhronizacija albumov", "sync_albums": "Sinhronizacija albumov",
"sync_albums_manual_subtitle": "Sinhronizirajte vse naložene videoposnetke in fotografije v izbrane varnostne albume", "sync_albums_manual_subtitle": "Sinhronizirajte vse naložene videoposnetke in fotografije v izbrane varnostne albume",
"sync_local": "Sinhroniziraj lokalno",
"sync_remote": "Sinhroniziraj oddaljeno",
"sync_upload_album_setting_subtitle": "Ustvarite in naložite svoje fotografije in videoposnetke v izbrane albume na Immich", "sync_upload_album_setting_subtitle": "Ustvarite in naložite svoje fotografije in videoposnetke v izbrane albume na Immich",
"tag": "Oznaka", "tag": "Oznaka",
"tag_assets": "Označi sredstva", "tag_assets": "Označi sredstva",
@@ -1841,6 +1861,7 @@
"tag_updated": "Posodobljena oznaka: {tag}", "tag_updated": "Posodobljena oznaka: {tag}",
"tagged_assets": "Označeno {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}}", "tagged_assets": "Označeno {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}}",
"tags": "Oznake", "tags": "Oznake",
"tap_to_run_job": "Dotaknite se za zagon opravila",
"template": "Predloga", "template": "Predloga",
"theme": "Tema", "theme": "Tema",
"theme_selection": "Izbira teme", "theme_selection": "Izbira teme",
+22 -1
View File
@@ -573,6 +573,8 @@
"backup_options_page_title": "备份选项", "backup_options_page_title": "备份选项",
"backup_setting_subtitle": "管理后台和前台上传设置", "backup_setting_subtitle": "管理后台和前台上传设置",
"backward": "后退", "backward": "后退",
"beta_sync": "测试版同步状态",
"beta_sync_subtitle": "管理新的同步系统",
"biometric_auth_enabled": "生物识别身份验证已启用", "biometric_auth_enabled": "生物识别身份验证已启用",
"biometric_locked_out": "您被锁定在生物识别身份验证之外", "biometric_locked_out": "您被锁定在生物识别身份验证之外",
"biometric_no_options": "没有可用的生物识别选项", "biometric_no_options": "没有可用的生物识别选项",
@@ -590,7 +592,7 @@
"cache_settings_clear_cache_button": "清除缓存", "cache_settings_clear_cache_button": "清除缓存",
"cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。", "cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
"cache_settings_duplicated_assets_clear_button": "清除", "cache_settings_duplicated_assets_clear_button": "清除",
"cache_settings_duplicated_assets_subtitle": "已加入黑名单的照片和视频", "cache_settings_duplicated_assets_subtitle": "应用程序忽略的照片和视频",
"cache_settings_duplicated_assets_title": "重复项目({count}", "cache_settings_duplicated_assets_title": "重复项目({count}",
"cache_settings_statistics_album": "图库缩略图", "cache_settings_statistics_album": "图库缩略图",
"cache_settings_statistics_full": "完整图像", "cache_settings_statistics_full": "完整图像",
@@ -1051,6 +1053,9 @@
"haptic_feedback_switch": "启用振动反馈", "haptic_feedback_switch": "启用振动反馈",
"haptic_feedback_title": "振动反馈", "haptic_feedback_title": "振动反馈",
"has_quota": "配额大小", "has_quota": "配额大小",
"hash_asset": "哈希项目",
"hashed_assets": "已哈希的项目",
"hashing": "正在哈希",
"header_settings_add_header_tip": "添加标头", "header_settings_add_header_tip": "添加标头",
"header_settings_field_validator_msg": "设置不可为空", "header_settings_field_validator_msg": "设置不可为空",
"header_settings_header_name_input": "标头名称", "header_settings_header_name_input": "标头名称",
@@ -1083,6 +1088,7 @@
"host": "服务器", "host": "服务器",
"hour": "时", "hour": "时",
"id": "ID", "id": "ID",
"idle": "空闲",
"ignore_icloud_photos": "忽略 iCloud 照片", "ignore_icloud_photos": "忽略 iCloud 照片",
"ignore_icloud_photos_description": "存储在 iCloud 中的照片不会上传至 Immich 服务器", "ignore_icloud_photos_description": "存储在 iCloud 中的照片不会上传至 Immich 服务器",
"image": "图片", "image": "图片",
@@ -1165,7 +1171,9 @@
"list": "列表", "list": "列表",
"loading": "加载中", "loading": "加载中",
"loading_search_results_failed": "加载搜索结果失败", "loading_search_results_failed": "加载搜索结果失败",
"local": "本地",
"local_asset_cast_failed": "无法投放未上传至服务器的项目", "local_asset_cast_failed": "无法投放未上传至服务器的项目",
"local_assets": "本地项目",
"local_network": "本地网络", "local_network": "本地网络",
"local_network_sheet_info": "当使用指定的 Wi-Fi 网络时,应用程序将通过此 URL 访问服务器", "local_network_sheet_info": "当使用指定的 Wi-Fi 网络时,应用程序将通过此 URL 访问服务器",
"location_permission": "定位权限", "location_permission": "定位权限",
@@ -1322,6 +1330,7 @@
"no_results": "无结果", "no_results": "无结果",
"no_results_description": "尝试使用同义词或更通用的关键词", "no_results_description": "尝试使用同义词或更通用的关键词",
"no_shared_albums_message": "创建相册以共享照片和视频", "no_shared_albums_message": "创建相册以共享照片和视频",
"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_apply_storage_label_to_previously_uploaded assets": "提示:要将存储标签应用于之前上传的项目,需要运行",
@@ -1359,6 +1368,7 @@
"original": "原图", "original": "原图",
"other": "其它", "other": "其它",
"other_devices": "其它设备", "other_devices": "其它设备",
"other_entities": "其他实体",
"other_variables": "其它变量", "other_variables": "其它变量",
"owned": "我的", "owned": "我的",
"owner": "所有者", "owner": "所有者",
@@ -1519,6 +1529,8 @@
"refreshing_faces": "正在面部重新识别", "refreshing_faces": "正在面部重新识别",
"refreshing_metadata": "正在刷新元数据", "refreshing_metadata": "正在刷新元数据",
"regenerating_thumbnails": "正在重新生成缩略图", "regenerating_thumbnails": "正在重新生成缩略图",
"remote": "远程",
"remote_assets": "远程项目",
"remove": "移除", "remove": "移除",
"remove_assets_album_confirmation": "确定要从图库中移除{count, plural, one {#个项目} other {#个项目}}", "remove_assets_album_confirmation": "确定要从图库中移除{count, plural, one {#个项目} other {#个项目}}",
"remove_assets_shared_link_confirmation": "确定要从共享链接中移除{count, plural, one {#个项目} other {#个项目}}", "remove_assets_shared_link_confirmation": "确定要从共享链接中移除{count, plural, one {#个项目} other {#个项目}}",
@@ -1556,11 +1568,15 @@
"reset_password": "重置密码", "reset_password": "重置密码",
"reset_people_visibility": "重置人物识别", "reset_people_visibility": "重置人物识别",
"reset_pin_code": "重置PIN码", "reset_pin_code": "重置PIN码",
"reset_sqlite": "重置 SQLite 数据库",
"reset_sqlite_confirmation": "您确定要重置 SQLite 数据库吗?您需要注销并重新登录才能重新同步数据",
"reset_sqlite_success": "已成功重置 SQLite 数据库",
"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} 项",
"restore_user": "恢复用户", "restore_user": "恢复用户",
"restored_asset": "已恢复项目", "restored_asset": "已恢复项目",
"resume": "继续", "resume": "继续",
@@ -1569,6 +1585,7 @@
"role": "选择用户权限", "role": "选择用户权限",
"role_editor": "可编辑", "role_editor": "可编辑",
"role_viewer": "仅查看", "role_viewer": "仅查看",
"running": "正在运行",
"save": "保存", "save": "保存",
"save_to_gallery": "保存到图库", "save_to_gallery": "保存到图库",
"saved_api_key": "已保存的 API 密钥", "saved_api_key": "已保存的 API 密钥",
@@ -1822,6 +1839,7 @@
"storage_quota": "存储配额", "storage_quota": "存储配额",
"storage_usage": "已用:{used}/{available}", "storage_usage": "已用:{used}/{available}",
"submit": "提交", "submit": "提交",
"success": "成功",
"suggestions": "建议", "suggestions": "建议",
"sunrise_on_the_beach": "海滩上的日出", "sunrise_on_the_beach": "海滩上的日出",
"support": "支持", "support": "支持",
@@ -1831,6 +1849,8 @@
"sync": "同步", "sync": "同步",
"sync_albums": "同步相册", "sync_albums": "同步相册",
"sync_albums_manual_subtitle": "将所有上传的视频和照片同步到选定的备份相册", "sync_albums_manual_subtitle": "将所有上传的视频和照片同步到选定的备份相册",
"sync_local": "同步本地",
"sync_remote": "同步远程",
"sync_upload_album_setting_subtitle": "创建照片和视频并上传到 Immich 上的选定相册中", "sync_upload_album_setting_subtitle": "创建照片和视频并上传到 Immich 上的选定相册中",
"tag": "标签", "tag": "标签",
"tag_assets": "标记项目", "tag_assets": "标记项目",
@@ -1841,6 +1861,7 @@
"tag_updated": "已更新标签:{tag}", "tag_updated": "已更新标签:{tag}",
"tagged_assets": "{count, plural, one {# 个项目} other {# 个项目}}被加上标签", "tagged_assets": "{count, plural, one {# 个项目} other {# 个项目}}被加上标签",
"tags": "标签", "tags": "标签",
"tap_to_run_job": "点击运行作业",
"template": "模版", "template": "模版",
"theme": "主题", "theme": "主题",
"theme_selection": "主题选项", "theme_selection": "主题选项",
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"flutter": "3.32.6" "flutter": "3.32.8"
} }
+5 -1
View File
@@ -1,5 +1,9 @@
{ {
"dart.flutterSdkPath": ".fvm/versions/3.32.6", "dart.flutterSdkPath": ".fvm/versions/3.32.8",
"dart.lineLength": 120,
"[dart]": {
"editor.rulers": [120],
},
"search.exclude": { "search.exclude": {
"**/.fvm": true "**/.fvm": true
}, },
+3
View File
@@ -9,6 +9,9 @@
# packages, and plugins designed to encourage good coding practices. # packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml
formatter:
page_width: 120
linter: linter:
# The lint rules applied to this project can be customized in the # The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml` # section below to disable rules from the `package:flutter_lints/flutter.yaml`
-14
View File
@@ -72,20 +72,6 @@ android {
} }
} }
flavorDimensions "default"
productFlavors {
production {
dimension "default"
applicationId "app.alextran.immich"
}
beta {
dimension "default"
applicationId "app.alextran.immich.beta"
versionNameSuffix "-BETA"
}
}
buildTypes { buildTypes {
debug { debug {
applicationIdSuffix '.debug' applicationIdSuffix '.debug'
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application android:label="Immich Beta" tools:replace="android:label" />
</manifest>
@@ -88,7 +88,8 @@ data class PlatformAsset (
val width: Long? = null, val width: Long? = null,
val height: Long? = null, val height: Long? = null,
val durationInSeconds: Long, val durationInSeconds: Long,
val orientation: Long val orientation: Long,
val isFavorite: Boolean
) )
{ {
companion object { companion object {
@@ -102,7 +103,8 @@ data class PlatformAsset (
val height = pigeonVar_list[6] as Long? val height = pigeonVar_list[6] as Long?
val durationInSeconds = pigeonVar_list[7] as Long val durationInSeconds = pigeonVar_list[7] as Long
val orientation = pigeonVar_list[8] as Long val orientation = pigeonVar_list[8] as Long
return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation) val isFavorite = pigeonVar_list[9] as Boolean
return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation, isFavorite)
} }
} }
fun toList(): List<Any?> { fun toList(): List<Any?> {
@@ -116,6 +118,7 @@ data class PlatformAsset (
height, height,
durationInSeconds, durationInSeconds,
orientation, orientation,
isFavorite,
) )
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
@@ -42,6 +42,7 @@ open class NativeSyncApiImplBase(context: Context) {
MediaStore.MediaColumns.HEIGHT, MediaStore.MediaColumns.HEIGHT,
MediaStore.MediaColumns.DURATION, MediaStore.MediaColumns.DURATION,
MediaStore.MediaColumns.ORIENTATION, MediaStore.MediaColumns.ORIENTATION,
MediaStore.MediaColumns.IS_FAVORITE,
) )
const val HASH_BUFFER_SIZE = 2 * 1024 * 1024 const val HASH_BUFFER_SIZE = 2 * 1024 * 1024
@@ -77,6 +78,7 @@ open class NativeSyncApiImplBase(context: Context) {
val durationColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.DURATION) val durationColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.DURATION)
val orientationColumn = val orientationColumn =
c.getColumnIndexOrThrow(MediaStore.MediaColumns.ORIENTATION) c.getColumnIndexOrThrow(MediaStore.MediaColumns.ORIENTATION)
val favoriteColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.IS_FAVORITE)
while (c.moveToNext()) { while (c.moveToNext()) {
val id = c.getLong(idColumn).toString() val id = c.getLong(idColumn).toString()
@@ -105,6 +107,7 @@ open class NativeSyncApiImplBase(context: Context) {
else c.getLong(durationColumn) / 1000 else c.getLong(durationColumn) / 1000
val bucketId = c.getString(bucketIdColumn) val bucketId = c.getString(bucketIdColumn)
val orientation = c.getInt(orientationColumn) val orientation = c.getInt(orientationColumn)
val isFavorite = c.getInt(favoriteColumn) != 0;
val asset = PlatformAsset( val asset = PlatformAsset(
id, id,
@@ -116,6 +119,7 @@ open class NativeSyncApiImplBase(context: Context) {
height, height,
duration, duration,
orientation.toLong(), orientation.toLong(),
isFavorite,
) )
yield(AssetResult.ValidAsset(asset, bucketId)) yield(AssetResult.ValidAsset(asset, bucketId))
} }
@@ -69,7 +69,7 @@ class ImageDownloadWorker(
.build() .build()
manager.enqueueUniqueWork( manager.enqueueUniqueWork(
"$uniqueWorkName-$appWidgetId", "$uniqueWorkName-$appWidgetId-singleShot",
ExistingWorkPolicy.REPLACE, ExistingWorkPolicy.REPLACE,
workRequest workRequest
) )
@@ -28,19 +28,21 @@ class MemoryReceiver : GlanceAppWidgetReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
val fromMainApp = intent.getBooleanExtra(HomeWidgetPlugin.TRIGGERED_FROM_HOME_WIDGET, false) val fromMainApp = intent.getBooleanExtra(HomeWidgetPlugin.TRIGGERED_FROM_HOME_WIDGET, false)
val provider = ComponentName(context, MemoryReceiver::class.java)
val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider)
// Launch coroutine to setup a single shot if the app requested the update // Launch coroutine to setup a single shot if the app requested the update
if (fromMainApp) { if (fromMainApp) {
CoroutineScope(Dispatchers.Default).launch { glanceIds.forEach { widgetID ->
val provider = ComponentName(context, MemoryReceiver::class.java) ImageDownloadWorker.singleShot(context, widgetID, WidgetType.MEMORIES)
val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider)
glanceIds.forEach { widgetID ->
ImageDownloadWorker.singleShot(context, widgetID, WidgetType.MEMORIES)
}
} }
} }
// make sure the periodic jobs are running
glanceIds.forEach { widgetID ->
ImageDownloadWorker.enqueuePeriodic(context, widgetID, WidgetType.MEMORIES)
}
super.onReceive(context, intent) super.onReceive(context, intent)
} }
@@ -28,19 +28,21 @@ class RandomReceiver : GlanceAppWidgetReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
val fromMainApp = intent.getBooleanExtra(HomeWidgetPlugin.TRIGGERED_FROM_HOME_WIDGET, false) val fromMainApp = intent.getBooleanExtra(HomeWidgetPlugin.TRIGGERED_FROM_HOME_WIDGET, false)
val provider = ComponentName(context, RandomReceiver::class.java)
val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider)
// Launch coroutine to setup a single shot if the app requested the update // Launch coroutine to setup a single shot if the app requested the update
if (fromMainApp) { if (fromMainApp) {
CoroutineScope(Dispatchers.Default).launch { glanceIds.forEach { widgetID ->
val provider = ComponentName(context, RandomReceiver::class.java) ImageDownloadWorker.singleShot(context, widgetID, WidgetType.RANDOM)
val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider)
glanceIds.forEach { widgetID ->
ImageDownloadWorker.singleShot(context, widgetID, WidgetType.RANDOM)
}
} }
} }
// make sure the periodic jobs are running
glanceIds.forEach { widgetID ->
ImageDownloadWorker.enqueuePeriodic(context, widgetID, WidgetType.RANDOM)
}
super.onReceive(context, intent) super.onReceive(context, intent)
} }
+2 -2
View File
@@ -35,8 +35,8 @@ platform :android do
task: 'bundle', task: 'bundle',
build_type: 'Release', build_type: 'Release',
properties: { properties: {
"android.injected.version.code" => 204, "android.injected.version.code" => 205,
"android.injected.version.name" => "1.135.3", "android.injected.version.name" => "1.136.0",
} }
) )
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5 -1
View File
@@ -139,6 +139,7 @@ struct PlatformAsset: Hashable {
var height: Int64? = nil var height: Int64? = nil
var durationInSeconds: Int64 var durationInSeconds: Int64
var orientation: Int64 var orientation: Int64
var isFavorite: Bool
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
@@ -152,6 +153,7 @@ struct PlatformAsset: Hashable {
let height: Int64? = nilOrValue(pigeonVar_list[6]) let height: Int64? = nilOrValue(pigeonVar_list[6])
let durationInSeconds = pigeonVar_list[7] as! Int64 let durationInSeconds = pigeonVar_list[7] as! Int64
let orientation = pigeonVar_list[8] as! Int64 let orientation = pigeonVar_list[8] as! Int64
let isFavorite = pigeonVar_list[9] as! Bool
return PlatformAsset( return PlatformAsset(
id: id, id: id,
@@ -162,7 +164,8 @@ struct PlatformAsset: Hashable {
width: width, width: width,
height: height, height: height,
durationInSeconds: durationInSeconds, durationInSeconds: durationInSeconds,
orientation: orientation orientation: orientation,
isFavorite: isFavorite
) )
} }
func toList() -> [Any?] { func toList() -> [Any?] {
@@ -176,6 +179,7 @@ struct PlatformAsset: Hashable {
height, height,
durationInSeconds, durationInSeconds,
orientation, orientation,
isFavorite,
] ]
} }
static func == (lhs: PlatformAsset, rhs: PlatformAsset) -> Bool { static func == (lhs: PlatformAsset, rhs: PlatformAsset) -> Bool {
+4 -2
View File
@@ -28,7 +28,8 @@ extension PHAsset {
width: Int64(pixelWidth), width: Int64(pixelWidth),
height: Int64(pixelHeight), height: Int64(pixelHeight),
durationInSeconds: Int64(duration), durationInSeconds: Int64(duration),
orientation: 0 orientation: 0,
isFavorite: isFavorite
) )
} }
} }
@@ -171,7 +172,8 @@ class NativeSyncApiImpl: NativeSyncApi {
name: "", name: "",
type: 0, type: 0,
durationInSeconds: 0, durationInSeconds: 0,
orientation: 0 orientation: 0,
isFavorite: false
) )
if (updatedAssets.contains(AssetWrapper(with: predicate))) { if (updatedAssets.contains(AssetWrapper(with: predicate))) {
continue continue
+1 -1
View File
@@ -22,7 +22,7 @@ platform :ios do
path: "./Runner.xcodeproj", path: "./Runner.xcodeproj",
) )
increment_version_number( increment_version_number(
version_number: "1.135.3" version_number: "1.136.0"
) )
increment_build_number( increment_build_number(
build_number: latest_testflight_build_number + 1, build_number: latest_testflight_build_number + 1,
+1 -12
View File
@@ -1,17 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
enum ImmichColorPreset { enum ImmichColorPreset { indigo, deepPurple, pink, red, orange, yellow, lime, green, cyan, slateGray }
indigo,
deepPurple,
pink,
red,
orange,
yellow,
lime,
green,
cyan,
slateGray
}
const ImmichColorPreset defaultColorPreset = ImmichColorPreset.indigo; const ImmichColorPreset defaultColorPreset = ImmichColorPreset.indigo;
const String defaultColorPresetName = "indigo"; const String defaultColorPresetName = "indigo";
+2 -9
View File
@@ -1,13 +1,6 @@
enum SortOrder { enum SortOrder { asc, desc }
asc,
desc,
}
enum TextSearchType { enum TextSearchType { context, filename, description }
context,
filename,
description,
}
enum AssetVisibilityEnum { timeline, hidden, archive, locked } enum AssetVisibilityEnum { timeline, hidden, archive, locked }
+31 -682
View File
@@ -2,511 +2,49 @@ import 'package:flutter/material.dart';
const List<ColorFilter> filters = [ const List<ColorFilter> filters = [
//Original //Original
ColorFilter.matrix([ ColorFilter.matrix([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]),
1,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
1,
0,
]),
//Vintage //Vintage
ColorFilter.matrix([ ColorFilter.matrix([0.8, 0.1, 0.1, 0, 20, 0.1, 0.8, 0.1, 0, 20, 0.1, 0.1, 0.8, 0, 20, 0, 0, 0, 1, 0]),
0.8,
0.1,
0.1,
0,
20,
0.1,
0.8,
0.1,
0,
20,
0.1,
0.1,
0.8,
0,
20,
0,
0,
0,
1,
0,
]),
//Mood //Mood
ColorFilter.matrix([ ColorFilter.matrix([1.2, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 10, 0, 0, 0, 1, 0]),
1.2,
0.1,
0.1,
0,
10,
0.1,
1,
0.1,
0,
10,
0.1,
0.1,
1,
0,
10,
0,
0,
0,
1,
0,
]),
//Crisp //Crisp
ColorFilter.matrix([ ColorFilter.matrix([1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
1.2,
0,
0,
0,
0,
0,
1.2,
0,
0,
0,
0,
0,
1.2,
0,
0,
0,
0,
0,
1,
0,
]),
//Cool //Cool
ColorFilter.matrix([ ColorFilter.matrix([0.9, 0, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
0.9,
0,
0.2,
0,
0,
0,
1,
0.1,
0,
0,
0.1,
0,
1.2,
0,
0,
0,
0,
0,
1,
0,
]),
//Blush //Blush
ColorFilter.matrix([ ColorFilter.matrix([1.1, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 5, 0, 0, 0, 1, 0]),
1.1,
0.1,
0.1,
0,
10,
0.1,
1,
0.1,
0,
10,
0.1,
0.1,
1,
0,
5,
0,
0,
0,
1,
0,
]),
//Sunkissed //Sunkissed
ColorFilter.matrix([ ColorFilter.matrix([1.3, 0, 0.1, 0, 15, 0, 1.1, 0.1, 0, 10, 0, 0, 0.9, 0, 5, 0, 0, 0, 1, 0]),
1.3,
0,
0.1,
0,
15,
0,
1.1,
0.1,
0,
10,
0,
0,
0.9,
0,
5,
0,
0,
0,
1,
0,
]),
//Fresh //Fresh
ColorFilter.matrix([ ColorFilter.matrix([1.2, 0, 0, 0, 20, 0, 1.2, 0, 0, 20, 0, 0, 1.1, 0, 20, 0, 0, 0, 1, 0]),
1.2,
0,
0,
0,
20,
0,
1.2,
0,
0,
20,
0,
0,
1.1,
0,
20,
0,
0,
0,
1,
0,
]),
//Classic //Classic
ColorFilter.matrix([ ColorFilter.matrix([1.1, 0, -0.1, 0, 10, -0.1, 1.1, 0.1, 0, 5, 0, -0.1, 1.1, 0, 0, 0, 0, 0, 1, 0]),
1.1,
0,
-0.1,
0,
10,
-0.1,
1.1,
0.1,
0,
5,
0,
-0.1,
1.1,
0,
0,
0,
0,
0,
1,
0,
]),
//Lomo-ish //Lomo-ish
ColorFilter.matrix([ ColorFilter.matrix([1.5, 0, 0.1, 0, 0, 0, 1.45, 0, 0, 0, 0.1, 0, 1.3, 0, 0, 0, 0, 0, 1, 0]),
1.5,
0,
0.1,
0,
0,
0,
1.45,
0,
0,
0,
0.1,
0,
1.3,
0,
0,
0,
0,
0,
1,
0,
]),
//Nashville //Nashville
ColorFilter.matrix([ ColorFilter.matrix([1.2, 0.15, -0.15, 0, 15, 0.1, 1.1, 0.1, 0, 10, -0.05, 0.2, 1.25, 0, 5, 0, 0, 0, 1, 0]),
1.2,
0.15,
-0.15,
0,
15,
0.1,
1.1,
0.1,
0,
10,
-0.05,
0.2,
1.25,
0,
5,
0,
0,
0,
1,
0,
]),
//Valencia //Valencia
ColorFilter.matrix([ ColorFilter.matrix([1.15, 0.1, 0.1, 0, 20, 0.1, 1.1, 0, 0, 10, 0.1, 0.1, 1.2, 0, 5, 0, 0, 0, 1, 0]),
1.15,
0.1,
0.1,
0,
20,
0.1,
1.1,
0,
0,
10,
0.1,
0.1,
1.2,
0,
5,
0,
0,
0,
1,
0,
]),
//Clarendon //Clarendon
ColorFilter.matrix([ ColorFilter.matrix([1.2, 0, 0, 0, 10, 0, 1.25, 0, 0, 10, 0, 0, 1.3, 0, 10, 0, 0, 0, 1, 0]),
1.2,
0,
0,
0,
10,
0,
1.25,
0,
0,
10,
0,
0,
1.3,
0,
10,
0,
0,
0,
1,
0,
]),
//Moon //Moon
ColorFilter.matrix([ ColorFilter.matrix([0.33, 0.33, 0.33, 0, 0, 0.33, 0.33, 0.33, 0, 0, 0.33, 0.33, 0.33, 0, 0, 0, 0, 0, 1, 0]),
0.33,
0.33,
0.33,
0,
0,
0.33,
0.33,
0.33,
0,
0,
0.33,
0.33,
0.33,
0,
0,
0,
0,
0,
1,
0,
]),
//Willow //Willow
ColorFilter.matrix([ ColorFilter.matrix([0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0, 0, 0, 1, 0]),
0.5,
0.5,
0.5,
0,
20,
0.5,
0.5,
0.5,
0,
20,
0.5,
0.5,
0.5,
0,
20,
0,
0,
0,
1,
0,
]),
//Kodak //Kodak
ColorFilter.matrix([ ColorFilter.matrix([1.3, 0.1, -0.1, 0, 10, 0, 1.25, 0.1, 0, 10, 0, -0.1, 1.1, 0, 5, 0, 0, 0, 1, 0]),
1.3,
0.1,
-0.1,
0,
10,
0,
1.25,
0.1,
0,
10,
0,
-0.1,
1.1,
0,
5,
0,
0,
0,
1,
0,
]),
//Frost //Frost
ColorFilter.matrix([ ColorFilter.matrix([0.8, 0.2, 0.1, 0, 0, 0.2, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.2, 0, 10, 0, 0, 0, 1, 0]),
0.8,
0.2,
0.1,
0,
0,
0.2,
1.1,
0.1,
0,
0,
0.1,
0.1,
1.2,
0,
10,
0,
0,
0,
1,
0,
]),
//Night Vision //Night Vision
ColorFilter.matrix([ ColorFilter.matrix([0.1, 0.95, 0.2, 0, 0, 0.1, 1.5, 0.1, 0, 0, 0.2, 0.7, 0, 0, 0, 0, 0, 0, 1, 0]),
0.1,
0.95,
0.2,
0,
0,
0.1,
1.5,
0.1,
0,
0,
0.2,
0.7,
0,
0,
0,
0,
0,
0,
1,
0,
]),
//Sunset //Sunset
ColorFilter.matrix([ ColorFilter.matrix([1.5, 0.2, 0, 0, 0, 0.1, 0.9, 0.1, 0, 0, -0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0]),
1.5,
0.2,
0,
0,
0,
0.1,
0.9,
0.1,
0,
0,
-0.1,
-0.2,
1.3,
0,
0,
0,
0,
0,
1,
0,
]),
//Noir //Noir
ColorFilter.matrix([ ColorFilter.matrix([1.3, -0.3, 0.1, 0, 0, -0.1, 1.2, -0.1, 0, 0, 0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0]),
1.3,
-0.3,
0.1,
0,
0,
-0.1,
1.2,
-0.1,
0,
0,
0.1,
-0.2,
1.3,
0,
0,
0,
0,
0,
1,
0,
]),
//Dreamy //Dreamy
ColorFilter.matrix([ ColorFilter.matrix([1.1, 0.1, 0.1, 0, 0, 0.1, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.1, 0, 15, 0, 0, 0, 1, 0]),
1.1,
0.1,
0.1,
0,
0,
0.1,
1.1,
0.1,
0,
0,
0.1,
0.1,
1.1,
0,
15,
0,
0,
0,
1,
0,
]),
//Sepia //Sepia
ColorFilter.matrix([ ColorFilter.matrix([0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0, 1, 0]),
0.393,
0.769,
0.189,
0,
0,
0.349,
0.686,
0.168,
0,
0,
0.272,
0.534,
0.131,
0,
0,
0,
0,
0,
1,
0,
]),
//Radium //Radium
ColorFilter.matrix([ ColorFilter.matrix([
1.438, 1.438,
@@ -554,212 +92,23 @@ const List<ColorFilter> filters = [
0, 0,
]), ]),
//Purple Haze //Purple Haze
ColorFilter.matrix([ ColorFilter.matrix([1.3, 0, 1.2, 0, 0, 0, 1.1, 0, 0, 0, 0.2, 0, 1.3, 0, 0, 0, 0, 0, 1, 0]),
1.3,
0,
1.2,
0,
0,
0,
1.1,
0,
0,
0,
0.2,
0,
1.3,
0,
0,
0,
0,
0,
1,
0,
]),
//Lemonade //Lemonade
ColorFilter.matrix([ ColorFilter.matrix([1.2, 0.1, 0, 0, 0, 0, 1.1, 0.2, 0, 0, 0.1, 0, 0.7, 0, 0, 0, 0, 0, 1, 0]),
1.2,
0.1,
0,
0,
0,
0,
1.1,
0.2,
0,
0,
0.1,
0,
0.7,
0,
0,
0,
0,
0,
1,
0,
]),
//Caramel //Caramel
ColorFilter.matrix([ ColorFilter.matrix([1.6, 0.2, 0, 0, 0, 0.1, 1.3, 0.1, 0, 0, 0, 0.1, 0.9, 0, 0, 0, 0, 0, 1, 0]),
1.6,
0.2,
0,
0,
0,
0.1,
1.3,
0.1,
0,
0,
0,
0.1,
0.9,
0,
0,
0,
0,
0,
1,
0,
]),
//Peachy //Peachy
ColorFilter.matrix([ ColorFilter.matrix([1.3, 0.5, 0, 0, 0, 0.2, 1.1, 0.3, 0, 0, 0.1, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0]),
1.3,
0.5,
0,
0,
0,
0.2,
1.1,
0.3,
0,
0,
0.1,
0.1,
1.2,
0,
0,
0,
0,
0,
1,
0,
]),
//Neon //Neon
ColorFilter.matrix([ ColorFilter.matrix([1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0]),
1,
0,
1,
0,
0,
0,
2,
0,
0,
0,
0,
0,
3,
0,
0,
0,
0,
0,
1,
0,
]),
//Cold Morning //Cold Morning
ColorFilter.matrix([ ColorFilter.matrix([0.9, 0.1, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
0.9,
0.1,
0.2,
0,
0,
0,
1,
0.1,
0,
0,
0.1,
0,
1.2,
0,
0,
0,
0,
0,
1,
0,
]),
//Lush //Lush
ColorFilter.matrix([ ColorFilter.matrix([0.9, 0.2, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 0, 1, 0]),
0.9,
0.2,
0,
0,
0,
0,
1.2,
0,
0,
0,
0,
0,
1.1,
0,
0,
0,
0,
0,
1,
0,
]),
//Urban Neon //Urban Neon
ColorFilter.matrix([ ColorFilter.matrix([1.1, 0, 0.3, 0, 0, 0, 0.9, 0.3, 0, 0, 0.3, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0]),
1.1,
0,
0.3,
0,
0,
0,
0.9,
0.3,
0,
0,
0.3,
0.1,
1.2,
0,
0,
0,
0,
0,
1,
0,
]),
//Monochrome //Monochrome
ColorFilter.matrix([ ColorFilter.matrix([0.6, 0.2, 0.2, 0, 0, 0.2, 0.6, 0.2, 0, 0, 0.2, 0.2, 0.7, 0, 0, 0, 0, 0, 1, 0]),
0.6,
0.2,
0.2,
0,
0,
0.2,
0.6,
0.2,
0,
0,
0.2,
0.2,
0.7,
0,
0,
0,
0,
0,
1,
0,
]),
]; ];
const List<String> filterNames = [ const List<String> filterNames = [
+5 -12
View File
@@ -7,10 +7,8 @@ const Map<String, Locale> locales = {
'Arabic (ar)': Locale('ar'), 'Arabic (ar)': Locale('ar'),
'Bulgarian (bg)': Locale('bg'), 'Bulgarian (bg)': Locale('bg'),
'Catalan (ca)': Locale('ca'), 'Catalan (ca)': Locale('ca'),
'Chinese Simplified (zh_CN)': 'Chinese Simplified (zh_CN)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'), 'Chinese Traditional (zh_TW)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
'Chinese Traditional (zh_TW)':
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
'Croatian (hr)': Locale('hr'), 'Croatian (hr)': Locale('hr'),
'Czech (cs)': Locale('cs'), 'Czech (cs)': Locale('cs'),
'Danish (da)': Locale('da'), 'Danish (da)': Locale('da'),
@@ -37,10 +35,8 @@ const Map<String, Locale> locales = {
'Portuguese (pt)': Locale('pt'), 'Portuguese (pt)': Locale('pt'),
'Romanian (ro)': Locale('ro'), 'Romanian (ro)': Locale('ro'),
'Russian (ru)': Locale('ru'), 'Russian (ru)': Locale('ru'),
'Serbian Cyrillic (sr_Cyrl)': 'Serbian Cyrillic (sr_Cyrl)': Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Cyrl'),
Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Cyrl'), 'Serbian Latin (sr_Latn)': Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Latn'),
'Serbian Latin (sr_Latn)':
Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Latn'),
'Slovak (sk)': Locale('sk'), 'Slovak (sk)': Locale('sk'),
'Slovenian (sl)': Locale('sl'), 'Slovenian (sl)': Locale('sl'),
'Spanish (es)': Locale('es'), 'Spanish (es)': Locale('es'),
@@ -55,7 +51,4 @@ const Map<String, Locale> locales = {
const String translationsPath = 'assets/i18n'; const String translationsPath = 'assets/i18n';
const List<Locale> localesNotSupportedByOverpass = [ const List<Locale> localesNotSupportedByOverpass = [Locale('el', 'GR'), Locale('sr', 'Cyrl')];
Locale('el', 'GR'),
Locale('sr', 'Cyrl'),
];
@@ -9,11 +9,7 @@ enum AssetType {
audio, audio,
} }
enum AssetState { enum AssetState { local, remote, merged }
local,
remote,
merged,
}
sealed class BaseAsset { sealed class BaseAsset {
final String name; final String name;
@@ -53,10 +49,8 @@ sealed class BaseAsset {
return const Duration(); return const Duration();
} }
bool get hasRemote => bool get hasRemote => storage == AssetState.remote || storage == AssetState.merged;
storage == AssetState.remote || storage == AssetState.merged; bool get hasLocal => storage == AssetState.local || storage == AssetState.merged;
bool get hasLocal =>
storage == AssetState.local || storage == AssetState.merged;
bool get isLocalOnly => storage == AssetState.local; bool get isLocalOnly => storage == AssetState.local;
bool get isRemoteOnly => storage == AssetState.remote; bool get isRemoteOnly => storage == AssetState.remote;
@@ -22,8 +22,7 @@ class LocalAsset extends BaseAsset {
}); });
@override @override
AssetState get storage => AssetState get storage => remoteId == null ? AssetState.local : AssetState.merged;
remoteId == null ? AssetState.local : AssetState.merged;
@override @override
String get heroTag => '${id}_${remoteId ?? checksum}'; String get heroTag => '${id}_${remoteId ?? checksum}';
@@ -54,8 +53,7 @@ class LocalAsset extends BaseAsset {
} }
@override @override
int get hashCode => int get hashCode => super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode;
super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode;
LocalAsset copyWith({ LocalAsset copyWith({
String? id, String? id,
@@ -1,11 +1,6 @@
part of 'base_asset.model.dart'; part of 'base_asset.model.dart';
enum AssetVisibility { enum AssetVisibility { timeline, hidden, archive, locked }
timeline,
hidden,
archive,
locked,
}
// Model for an asset stored in the server // Model for an asset stored in the server
class RemoteAsset extends BaseAsset { class RemoteAsset extends BaseAsset {
@@ -15,7 +10,6 @@ class RemoteAsset extends BaseAsset {
final AssetVisibility visibility; final AssetVisibility visibility;
final String ownerId; final String ownerId;
final String? stackId; final String? stackId;
final int stackCount;
const RemoteAsset({ const RemoteAsset({
required this.id, required this.id,
@@ -34,12 +28,10 @@ class RemoteAsset extends BaseAsset {
this.visibility = AssetVisibility.timeline, this.visibility = AssetVisibility.timeline,
super.livePhotoVideoId, super.livePhotoVideoId,
this.stackId, this.stackId,
this.stackCount = 0,
}); });
@override @override
AssetState get storage => AssetState get storage => localId == null ? AssetState.remote : AssetState.merged;
localId == null ? AssetState.remote : AssetState.merged;
@override @override
String get heroTag => '${localId ?? checksum}_$id'; String get heroTag => '${localId ?? checksum}_$id';
@@ -61,7 +53,6 @@ class RemoteAsset extends BaseAsset {
thumbHash: ${thumbHash ?? "<NA>"}, thumbHash: ${thumbHash ?? "<NA>"},
visibility: $visibility, visibility: $visibility,
stackId: ${stackId ?? "<NA>"}, stackId: ${stackId ?? "<NA>"},
stackCount: $stackCount,
checksum: $checksum, checksum: $checksum,
livePhotoVideoId: ${livePhotoVideoId ?? "<NA>"}, livePhotoVideoId: ${livePhotoVideoId ?? "<NA>"},
}'''; }''';
@@ -77,8 +68,7 @@ class RemoteAsset extends BaseAsset {
ownerId == other.ownerId && ownerId == other.ownerId &&
thumbHash == other.thumbHash && thumbHash == other.thumbHash &&
visibility == other.visibility && visibility == other.visibility &&
stackId == other.stackId && stackId == other.stackId;
stackCount == other.stackCount;
} }
@override @override
@@ -89,8 +79,7 @@ class RemoteAsset extends BaseAsset {
localId.hashCode ^ localId.hashCode ^
thumbHash.hashCode ^ thumbHash.hashCode ^
visibility.hashCode ^ visibility.hashCode ^
stackId.hashCode ^ stackId.hashCode;
stackCount.hashCode;
RemoteAsset copyWith({ RemoteAsset copyWith({
String? id, String? id,
@@ -109,7 +98,6 @@ class RemoteAsset extends BaseAsset {
AssetVisibility? visibility, AssetVisibility? visibility,
String? livePhotoVideoId, String? livePhotoVideoId,
String? stackId, String? stackId,
int? stackCount,
}) { }) {
return RemoteAsset( return RemoteAsset(
id: id ?? this.id, id: id ?? this.id,
@@ -128,7 +116,6 @@ class RemoteAsset extends BaseAsset {
visibility: visibility ?? this.visibility, visibility: visibility ?? this.visibility,
livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId,
stackId: stackId ?? this.stackId, stackId: stackId ?? this.stackId,
stackCount: stackCount ?? this.stackCount,
); );
} }
} }
@@ -5,19 +5,13 @@ class DeviceAsset {
final Uint8List hash; final Uint8List hash;
final DateTime modifiedTime; final DateTime modifiedTime;
const DeviceAsset({ const DeviceAsset({required this.assetId, required this.hash, required this.modifiedTime});
required this.assetId,
required this.hash,
required this.modifiedTime,
});
@override @override
bool operator ==(covariant DeviceAsset other) { bool operator ==(covariant DeviceAsset other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return other.assetId == assetId && return other.assetId == assetId && other.hash == hash && other.modifiedTime == modifiedTime;
other.hash == hash &&
other.modifiedTime == modifiedTime;
} }
@override @override
@@ -30,11 +24,7 @@ class DeviceAsset {
return 'DeviceAsset(assetId: $assetId, hash: $hash, modifiedTime: $modifiedTime)'; return 'DeviceAsset(assetId: $assetId, hash: $hash, modifiedTime: $modifiedTime)';
} }
DeviceAsset copyWith({ DeviceAsset copyWith({String? assetId, Uint8List? hash, DateTime? modifiedTime}) {
String? assetId,
Uint8List? hash,
DateTime? modifiedTime,
}) {
return DeviceAsset( return DeviceAsset(
assetId: assetId ?? this.assetId, assetId: assetId ?? this.assetId,
hash: hash ?? this.hash, hash: hash ?? this.hash,
+1 -2
View File
@@ -25,8 +25,7 @@ class ExifInfo {
final int? iso; final int? iso;
final double? exposureSeconds; final double? exposureSeconds;
bool get hasCoordinates => bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0;
latitude != null && longitude != null && latitude != 0 && longitude != 0;
String get exposureTime { String get exposureTime {
if (exposureSeconds == null) { if (exposureSeconds == null) {
+2 -18
View File
@@ -1,16 +1,5 @@
/// Log levels according to dart logging [Level] /// Log levels according to dart logging [Level]
enum LogLevel { enum LogLevel { all, finest, finer, fine, config, info, warning, severe, shout, off }
all,
finest,
finer,
fine,
config,
info,
warning,
severe,
shout,
off,
}
class LogMessage { class LogMessage {
final String message; final String message;
@@ -43,12 +32,7 @@ class LogMessage {
@override @override
int get hashCode { int get hashCode {
return message.hashCode ^ return message.hashCode ^ level.hashCode ^ createdAt.hashCode ^ logger.hashCode ^ error.hashCode ^ stack.hashCode;
level.hashCode ^
createdAt.hashCode ^
logger.hashCode ^
error.hashCode ^
stack.hashCode;
} }
@override @override
+18
View File
@@ -0,0 +1,18 @@
import 'package:maplibre_gl/maplibre_gl.dart';
class Marker {
final LatLng location;
final String assetId;
const Marker({required this.location, required this.assetId});
@override
bool operator ==(covariant Marker other) {
if (identical(this, other)) return true;
return other.location == location && other.assetId == assetId;
}
@override
int get hashCode => location.hashCode ^ assetId.hashCode;
}
+6 -17
View File
@@ -13,34 +13,23 @@ enum MemoryTypeEnum {
class MemoryData { class MemoryData {
final int year; final int year;
const MemoryData({ const MemoryData({required this.year});
required this.year,
});
MemoryData copyWith({ MemoryData copyWith({int? year}) {
int? year, return MemoryData(year: year ?? this.year);
}) {
return MemoryData(
year: year ?? this.year,
);
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return <String, dynamic>{ return <String, dynamic>{'year': year};
'year': year,
};
} }
factory MemoryData.fromMap(Map<String, dynamic> map) { factory MemoryData.fromMap(Map<String, dynamic> map) {
return MemoryData( return MemoryData(year: map['year'] as int);
year: map['year'] as int,
);
} }
String toJson() => json.encode(toMap()); String toJson() => json.encode(toMap());
factory MemoryData.fromJson(String source) => factory MemoryData.fromJson(String source) => MemoryData.fromMap(json.decode(source) as Map<String, dynamic>);
MemoryData.fromMap(json.decode(source) as Map<String, dynamic>);
@override @override
String toString() => 'MemoryData(year: $year)'; String toString() => 'MemoryData(year: $year)';
+8 -13
View File
@@ -55,22 +55,17 @@ class PersonDto {
factory PersonDto.fromMap(Map<String, dynamic> map) { factory PersonDto.fromMap(Map<String, dynamic> map) {
return PersonDto( return PersonDto(
id: map['id'] as String, id: map['id'] as String,
birthDate: map['birthDate'] != null birthDate: map['birthDate'] != null ? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int) : null,
? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int)
: null,
isHidden: map['isHidden'] as bool, isHidden: map['isHidden'] as bool,
name: map['name'] as String, name: map['name'] as String,
thumbnailPath: map['thumbnailPath'] as String, thumbnailPath: map['thumbnailPath'] as String,
updatedAt: map['updatedAt'] != null updatedAt: map['updatedAt'] != null ? DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int) : null,
? DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int)
: null,
); );
} }
String toJson() => json.encode(toMap()); String toJson() => json.encode(toMap());
factory PersonDto.fromJson(String source) => factory PersonDto.fromJson(String source) => PersonDto.fromMap(json.decode(source) as Map<String, dynamic>);
PersonDto.fromMap(json.decode(source) as Map<String, dynamic>);
@override @override
bool operator ==(covariant PersonDto other) { bool operator ==(covariant PersonDto other) {
@@ -96,7 +91,7 @@ class PersonDto {
} }
// Model for a person stored in the server // Model for a person stored in the server
class Person { class DriftPerson {
final String id; final String id;
final DateTime createdAt; final DateTime createdAt;
final DateTime updatedAt; final DateTime updatedAt;
@@ -108,7 +103,7 @@ class Person {
final String? color; final String? color;
final DateTime? birthDate; final DateTime? birthDate;
const Person({ const DriftPerson({
required this.id, required this.id,
required this.createdAt, required this.createdAt,
required this.updatedAt, required this.updatedAt,
@@ -121,7 +116,7 @@ class Person {
this.birthDate, this.birthDate,
}); });
Person copyWith({ DriftPerson copyWith({
String? id, String? id,
DateTime? createdAt, DateTime? createdAt,
DateTime? updatedAt, DateTime? updatedAt,
@@ -133,7 +128,7 @@ class Person {
String? color, String? color,
DateTime? birthDate, DateTime? birthDate,
}) { }) {
return Person( return DriftPerson(
id: id ?? this.id, id: id ?? this.id,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt, updatedAt: updatedAt ?? this.updatedAt,
@@ -164,7 +159,7 @@ class Person {
} }
@override @override
bool operator ==(covariant Person other) { bool operator ==(covariant DriftPerson other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return other.id == id && return other.id == id &&
@@ -5,21 +5,12 @@ class SearchResult {
final List<BaseAsset> assets; final List<BaseAsset> assets;
final int? nextPage; final int? nextPage;
const SearchResult({ const SearchResult({required this.assets, this.nextPage});
required this.assets,
this.nextPage,
});
int get totalAssets => assets.length; int get totalAssets => assets.length;
SearchResult copyWith({ SearchResult copyWith({List<BaseAsset>? assets, int? nextPage}) {
List<BaseAsset>? assets, return SearchResult(assets: assets ?? this.assets, nextPage: nextPage ?? this.nextPage);
int? nextPage,
}) {
return SearchResult(
assets: assets ?? this.assets,
nextPage: nextPage ?? this.nextPage,
);
} }
@override @override
+1 -1
View File
@@ -8,7 +8,7 @@ enum Setting<T> {
loadOriginalVideo<bool>(StoreKey.loadOriginalVideo, false), loadOriginalVideo<bool>(StoreKey.loadOriginalVideo, false),
preferRemoteImage<bool>(StoreKey.preferRemoteImage, false), preferRemoteImage<bool>(StoreKey.preferRemoteImage, false),
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, false), advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, false),
; enableBackup<bool>(StoreKey.enableBackup, false);
const Setting(this.storeKey, this.defaultValue); const Setting(this.storeKey, this.defaultValue);
+4 -20
View File
@@ -14,13 +14,7 @@ class Stack {
required this.primaryAssetId, required this.primaryAssetId,
}); });
Stack copyWith({ Stack copyWith({String? id, DateTime? createdAt, DateTime? updatedAt, String? ownerId, String? primaryAssetId}) {
String? id,
DateTime? createdAt,
DateTime? updatedAt,
String? ownerId,
String? primaryAssetId,
}) {
return Stack( return Stack(
id: id ?? this.id, id: id ?? this.id,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
@@ -54,11 +48,7 @@ class Stack {
@override @override
int get hashCode { int get hashCode {
return id.hashCode ^ return id.hashCode ^ createdAt.hashCode ^ updatedAt.hashCode ^ ownerId.hashCode ^ primaryAssetId.hashCode;
createdAt.hashCode ^
updatedAt.hashCode ^
ownerId.hashCode ^
primaryAssetId.hashCode;
} }
} }
@@ -67,19 +57,13 @@ class StackResponse {
final String primaryAssetId; final String primaryAssetId;
final List<String> assetIds; final List<String> assetIds;
const StackResponse({ const StackResponse({required this.id, required this.primaryAssetId, required this.assetIds});
required this.id,
required this.primaryAssetId,
required this.assetIds,
});
@override @override
bool operator ==(covariant StackResponse other) { bool operator ==(covariant StackResponse other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return other.id == id && return other.id == id && other.primaryAssetId == primaryAssetId && other.assetIds == assetIds;
other.primaryAssetId == primaryAssetId &&
other.assetIds == assetIds;
} }
@override @override
+12 -11
View File
@@ -1,17 +1,8 @@
import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/domain/utils/event_stream.dart';
enum GroupAssetsBy { enum GroupAssetsBy { day, month, auto, none }
day,
month,
none;
}
enum HeaderType { enum HeaderType { none, month, day, monthAndDay }
none,
month,
day,
monthAndDay;
}
class Bucket { class Bucket {
final int assetCount; final int assetCount;
@@ -44,3 +35,13 @@ class TimeBucket extends Bucket {
class TimelineReloadEvent extends Event { class TimelineReloadEvent extends Event {
const TimelineReloadEvent(); const TimelineReloadEvent();
} }
class ScrollToTopEvent extends Event {
const ScrollToTopEvent();
}
class ScrollToDateEvent extends Event {
final DateTime date;
const ScrollToDateEvent(this.date);
}
+19 -33
View File
@@ -74,22 +74,21 @@ quotaSizeInBytes: $quotaSizeInBytes,
bool? isPartnerSharedWith, bool? isPartnerSharedWith,
int? quotaUsageInBytes, int? quotaUsageInBytes,
int? quotaSizeInBytes, int? quotaSizeInBytes,
}) => }) => UserDto(
UserDto( id: id ?? this.id,
id: id ?? this.id, email: email ?? this.email,
email: email ?? this.email, name: name ?? this.name,
name: name ?? this.name, isAdmin: isAdmin ?? this.isAdmin,
isAdmin: isAdmin ?? this.isAdmin, updatedAt: updatedAt ?? this.updatedAt,
updatedAt: updatedAt ?? this.updatedAt, profileImagePath: profileImagePath ?? this.profileImagePath,
profileImagePath: profileImagePath ?? this.profileImagePath, avatarColor: avatarColor ?? this.avatarColor,
avatarColor: avatarColor ?? this.avatarColor, memoryEnabled: memoryEnabled ?? this.memoryEnabled,
memoryEnabled: memoryEnabled ?? this.memoryEnabled, inTimeline: inTimeline ?? this.inTimeline,
inTimeline: inTimeline ?? this.inTimeline, isPartnerSharedBy: isPartnerSharedBy ?? this.isPartnerSharedBy,
isPartnerSharedBy: isPartnerSharedBy ?? this.isPartnerSharedBy, isPartnerSharedWith: isPartnerSharedWith ?? this.isPartnerSharedWith,
isPartnerSharedWith: isPartnerSharedWith ?? this.isPartnerSharedWith, quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes, quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes,
quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes, );
);
@override @override
bool operator ==(covariant UserDto other) { bool operator ==(covariant UserDto other) {
@@ -143,13 +142,7 @@ class PartnerUserDto {
this.profileImagePath, this.profileImagePath,
}); });
PartnerUserDto copyWith({ PartnerUserDto copyWith({String? id, String? email, String? name, bool? inTimeline, String? profileImagePath}) {
String? id,
String? email,
String? name,
bool? inTimeline,
String? profileImagePath,
}) {
return PartnerUserDto( return PartnerUserDto(
id: id ?? this.id, id: id ?? this.id,
email: email ?? this.email, email: email ?? this.email,
@@ -175,16 +168,13 @@ class PartnerUserDto {
email: map['email'] as String, email: map['email'] as String,
name: map['name'] as String, name: map['name'] as String,
inTimeline: map['inTimeline'] as bool, inTimeline: map['inTimeline'] as bool,
profileImagePath: map['profileImagePath'] != null profileImagePath: map['profileImagePath'] != null ? map['profileImagePath'] as String : null,
? map['profileImagePath'] as String
: null,
); );
} }
String toJson() => json.encode(toMap()); String toJson() => json.encode(toMap());
factory PartnerUserDto.fromJson(String source) => factory PartnerUserDto.fromJson(String source) => PartnerUserDto.fromMap(json.decode(source) as Map<String, dynamic>);
PartnerUserDto.fromMap(json.decode(source) as Map<String, dynamic>);
@override @override
String toString() { String toString() {
@@ -204,10 +194,6 @@ class PartnerUserDto {
@override @override
int get hashCode { int get hashCode {
return id.hashCode ^ return id.hashCode ^ email.hashCode ^ name.hashCode ^ inTimeline.hashCode ^ profileImagePath.hashCode;
email.hashCode ^
name.hashCode ^
inTimeline.hashCode ^
profileImagePath.hashCode;
} }
} }
@@ -24,18 +24,17 @@ enum AvatarColor {
const AvatarColor(this.value); const AvatarColor(this.value);
Color toColor({bool isDarkTheme = false}) => switch (this) { Color toColor({bool isDarkTheme = false}) => switch (this) {
AvatarColor.primary => AvatarColor.primary => isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF),
isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF), AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182),
AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182), AvatarColor.red => const Color.fromARGB(255, 239, 68, 68),
AvatarColor.red => const Color.fromARGB(255, 239, 68, 68), AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8),
AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8), AvatarColor.blue => const Color.fromARGB(255, 59, 130, 246),
AvatarColor.blue => const Color.fromARGB(255, 59, 130, 246), AvatarColor.green => const Color.fromARGB(255, 22, 163, 74),
AvatarColor.green => const Color.fromARGB(255, 22, 163, 74), AvatarColor.purple => const Color.fromARGB(255, 147, 51, 234),
AvatarColor.purple => const Color.fromARGB(255, 147, 51, 234), AvatarColor.orange => const Color.fromARGB(255, 234, 88, 12),
AvatarColor.orange => const Color.fromARGB(255, 234, 88, 12), AvatarColor.gray => const Color.fromARGB(255, 75, 85, 99),
AvatarColor.gray => const Color.fromARGB(255, 75, 85, 99), AvatarColor.amber => const Color.fromARGB(255, 217, 119, 6),
AvatarColor.amber => const Color.fromARGB(255, 217, 119, 6), };
};
} }
class Onboarding { class Onboarding {
@@ -194,17 +193,9 @@ class License {
final String activationKey; final String activationKey;
final String licenseKey; final String licenseKey;
const License({ const License({required this.activatedAt, required this.activationKey, required this.licenseKey});
required this.activatedAt,
required this.activationKey,
required this.licenseKey,
});
License copyWith({ License copyWith({DateTime? activatedAt, String? activationKey, String? licenseKey}) {
DateTime? activatedAt,
String? activationKey,
String? licenseKey,
}) {
return License( return License(
activatedAt: activatedAt ?? this.activatedAt, activatedAt: activatedAt ?? this.activatedAt,
activationKey: activationKey ?? this.activationKey, activationKey: activationKey ?? this.activationKey,
@@ -241,14 +232,11 @@ licenseKey: $licenseKey,
bool operator ==(covariant License other) { bool operator ==(covariant License other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return activatedAt == other.activatedAt && return activatedAt == other.activatedAt && activationKey == other.activationKey && licenseKey == other.licenseKey;
activationKey == other.activationKey &&
licenseKey == other.licenseKey;
} }
@override @override
int get hashCode => int get hashCode => activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode;
activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode;
} }
// Model for a user metadata stored in the server // Model for a user metadata stored in the server
@@ -259,16 +247,11 @@ class UserMetadata {
final Preferences? preferences; final Preferences? preferences;
final License? license; final License? license;
const UserMetadata({ const UserMetadata({required this.userId, required this.key, this.onboarding, this.preferences, this.license})
required this.userId, : assert(
required this.key, onboarding != null || preferences != null || license != null,
this.onboarding, 'One of onboarding, preferences and license must be provided',
this.preferences, );
this.license,
}) : assert(
onboarding != null || preferences != null || license != null,
'One of onboarding, preferences and license must be provided',
);
UserMetadata copyWith({ UserMetadata copyWith({
String? userId, String? userId,
@@ -310,10 +293,6 @@ license: ${license ?? "<NA>"},
@override @override
int get hashCode { int get hashCode {
return userId.hashCode ^ return userId.hashCode ^ key.hashCode ^ onboarding.hashCode ^ preferences.hashCode ^ license.hashCode;
key.hashCode ^
onboarding.hashCode ^
preferences.hashCode ^
license.hashCode;
} }
} }
+11 -14
View File
@@ -13,15 +13,17 @@ class AssetService {
const AssetService({ const AssetService({
required RemoteAssetRepository remoteAssetRepository, required RemoteAssetRepository remoteAssetRepository,
required DriftLocalAssetRepository localAssetRepository, required DriftLocalAssetRepository localAssetRepository,
}) : _remoteAssetRepository = remoteAssetRepository, }) : _remoteAssetRepository = remoteAssetRepository,
_localAssetRepository = localAssetRepository, _localAssetRepository = localAssetRepository,
_platform = const LocalPlatform(); _platform = const LocalPlatform();
Stream<BaseAsset?> watchAsset(BaseAsset asset) { Stream<BaseAsset?> watchAsset(BaseAsset asset) {
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id; final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id;
return asset is LocalAsset return asset is LocalAsset ? _localAssetRepository.watchAsset(id) : _remoteAssetRepository.watchAsset(id);
? _localAssetRepository.watchAsset(id) }
: _remoteAssetRepository.watchAsset(id);
Future<RemoteAsset?> getRemoteAsset(String id) {
return _remoteAssetRepository.get(id);
} }
Future<List<RemoteAsset>> getStack(RemoteAsset asset) async { Future<List<RemoteAsset>> getStack(RemoteAsset asset) async {
@@ -40,8 +42,7 @@ class AssetService {
return null; return null;
} }
final id = final id = asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id;
asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id;
return _remoteAssetRepository.getExif(id); return _remoteAssetRepository.getExif(id);
} }
@@ -56,8 +57,7 @@ class AssetService {
width = exif?.width ?? asset.width?.toDouble(); width = exif?.width ?? asset.width?.toDouble();
height = exif?.height ?? asset.height?.toDouble(); height = exif?.height ?? asset.height?.toDouble();
} else if (asset is LocalAsset) { } else if (asset is LocalAsset) {
isFlipped = _platform.isAndroid && isFlipped = _platform.isAndroid && (asset.orientation == 90 || asset.orientation == 270);
(asset.orientation == 90 || asset.orientation == 270);
width = asset.width?.toDouble(); width = asset.width?.toDouble();
height = asset.height?.toDouble(); height = asset.height?.toDouble();
} else { } else {
@@ -78,10 +78,7 @@ class AssetService {
} }
Future<(int local, int remote)> getAssetCounts() async { Future<(int local, int remote)> getAssetCounts() async {
return ( return (await _localAssetRepository.getCount(), await _remoteAssetRepository.getCount());
await _localAssetRepository.getCount(),
await _remoteAssetRepository.getCount()
);
} }
Future<int> getLocalHashedCount() { Future<int> getLocalHashedCount() {
+7 -12
View File
@@ -25,24 +25,20 @@ class HashService {
required NativeSyncApi nativeSyncApi, required NativeSyncApi nativeSyncApi,
this.batchSizeLimit = kBatchHashSizeLimit, this.batchSizeLimit = kBatchHashSizeLimit,
this.batchFileLimit = kBatchHashFileLimit, this.batchFileLimit = kBatchHashFileLimit,
}) : _localAlbumRepository = localAlbumRepository, }) : _localAlbumRepository = localAlbumRepository,
_localAssetRepository = localAssetRepository, _localAssetRepository = localAssetRepository,
_storageRepository = storageRepository, _storageRepository = storageRepository,
_nativeSyncApi = nativeSyncApi; _nativeSyncApi = nativeSyncApi;
Future<void> hashAssets() async { Future<void> hashAssets() async {
final Stopwatch stopwatch = Stopwatch()..start(); final Stopwatch stopwatch = Stopwatch()..start();
// Sorted by backupSelection followed by isCloud // Sorted by backupSelection followed by isCloud
final localAlbums = await _localAlbumRepository.getAll( final localAlbums = await _localAlbumRepository.getAll(
sortBy: { sortBy: {SortLocalAlbumsBy.backupSelection, SortLocalAlbumsBy.isIosSharedAlbum},
SortLocalAlbumsBy.backupSelection,
SortLocalAlbumsBy.isIosSharedAlbum,
},
); );
for (final album in localAlbums) { for (final album in localAlbums) {
final assetsToHash = final assetsToHash = await _localAlbumRepository.getAssetsToHash(album.id);
await _localAlbumRepository.getAssetsToHash(album.id);
if (assetsToHash.isNotEmpty) { if (assetsToHash.isNotEmpty) {
await _hashAssets(assetsToHash); await _hashAssets(assetsToHash);
} }
@@ -88,8 +84,7 @@ class HashService {
_log.fine("Hashing ${toHash.length} files"); _log.fine("Hashing ${toHash.length} files");
final hashed = <LocalAsset>[]; final hashed = <LocalAsset>[];
final hashes = final hashes = await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList());
await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList());
assert( assert(
hashes.length == toHash.length, hashes.length == toHash.length,
"Hashes length does not match toHash length: ${hashes.length} != ${toHash.length}", "Hashes length does not match toHash length: ${hashes.length} != ${toHash.length}",
@@ -21,9 +21,9 @@ class LocalSyncService {
required DriftLocalAlbumRepository localAlbumRepository, required DriftLocalAlbumRepository localAlbumRepository,
required NativeSyncApi nativeSyncApi, required NativeSyncApi nativeSyncApi,
Platform? platform, Platform? platform,
}) : _localAlbumRepository = localAlbumRepository, }) : _localAlbumRepository = localAlbumRepository,
_nativeSyncApi = nativeSyncApi, _nativeSyncApi = nativeSyncApi,
_platform = platform ?? const LocalPlatform(); _platform = platform ?? const LocalPlatform();
Future<void> sync({bool full = false}) async { Future<void> sync({bool full = false}) async {
final Stopwatch stopwatch = Stopwatch()..start(); final Stopwatch stopwatch = Stopwatch()..start();
@@ -66,14 +66,11 @@ class LocalSyncService {
// On iOS, we need to full sync albums that are marked as cloud as the delta sync // On iOS, we need to full sync albums that are marked as cloud as the delta sync
// does not include changes for cloud albums. If ignoreIcloudAssets is enabled, // does not include changes for cloud albums. If ignoreIcloudAssets is enabled,
// remove the albums from the local database from the previous sync // remove the albums from the local database from the previous sync
final cloudAlbums = final cloudAlbums = deviceAlbums.where((a) => a.isCloud).toLocalAlbums();
deviceAlbums.where((a) => a.isCloud).toLocalAlbums();
for (final album in cloudAlbums) { for (final album in cloudAlbums) {
final dbAlbum = dbAlbums.firstWhereOrNull((a) => a.id == album.id); final dbAlbum = dbAlbums.firstWhereOrNull((a) => a.id == album.id);
if (dbAlbum == null) { if (dbAlbum == null) {
_log.warning( _log.warning("Cloud album ${album.name} not found in local database. Skipping sync.");
"Cloud album ${album.name} not found in local database. Skipping sync.",
);
continue; continue;
} }
await updateAlbum(dbAlbum, album); await updateAlbum(dbAlbum, album);
@@ -95,8 +92,7 @@ class LocalSyncService {
final Stopwatch stopwatch = Stopwatch()..start(); final Stopwatch stopwatch = Stopwatch()..start();
final deviceAlbums = await _nativeSyncApi.getAlbums(); final deviceAlbums = await _nativeSyncApi.getAlbums();
final dbAlbums = final dbAlbums = await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id});
await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id});
await diffSortedLists( await diffSortedLists(
dbAlbums, dbAlbums,
@@ -120,14 +116,9 @@ class LocalSyncService {
try { try {
_log.fine("Adding device album ${album.name}"); _log.fine("Adding device album ${album.name}");
final assets = album.assetCount > 0 final assets = album.assetCount > 0 ? await _nativeSyncApi.getAssetsForAlbum(album.id) : <PlatformAsset>[];
? await _nativeSyncApi.getAssetsForAlbum(album.id)
: <PlatformAsset>[];
await _localAlbumRepository.upsert( await _localAlbumRepository.upsert(album, toUpsert: assets.toLocalAssets());
album,
toUpsert: assets.toLocalAssets(),
);
_log.fine("Successfully added device album ${album.name}"); _log.fine("Successfully added device album ${album.name}");
} catch (e, s) { } catch (e, s) {
_log.warning("Error while adding device album", e, s); _log.warning("Error while adding device album", e, s);
@@ -150,9 +141,7 @@ class LocalSyncService {
_log.fine("Syncing device album ${dbAlbum.name}"); _log.fine("Syncing device album ${dbAlbum.name}");
if (_albumsEqual(deviceAlbum, dbAlbum)) { if (_albumsEqual(deviceAlbum, dbAlbum)) {
_log.fine( _log.fine("Device album ${dbAlbum.name} has not changed. Skipping sync.");
"Device album ${dbAlbum.name} has not changed. Skipping sync.",
);
return false; return false;
} }
@@ -176,10 +165,7 @@ class LocalSyncService {
@visibleForTesting @visibleForTesting
// The [deviceAlbum] is expected to be refreshed before calling this method // The [deviceAlbum] is expected to be refreshed before calling this method
// with modified time and asset count // with modified time and asset count
Future<bool> checkAddition( Future<bool> checkAddition(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async {
LocalAlbum dbAlbum,
LocalAlbum deviceAlbum,
) async {
try { try {
_log.fine("Fast syncing device album ${dbAlbum.name}"); _log.fine("Fast syncing device album ${dbAlbum.name}");
// Assets has been modified // Assets has been modified
@@ -188,16 +174,12 @@ class LocalSyncService {
return false; return false;
} }
final updatedTime = final updatedTime = (dbAlbum.updatedAt.millisecondsSinceEpoch ~/ 1000) + 1;
(dbAlbum.updatedAt.millisecondsSinceEpoch ~/ 1000) + 1; final newAssetsCount = await _nativeSyncApi.getAssetsCountSince(deviceAlbum.id, updatedTime);
final newAssetsCount =
await _nativeSyncApi.getAssetsCountSince(deviceAlbum.id, updatedTime);
// Early return if no new assets were found // Early return if no new assets were found
if (newAssetsCount == 0) { if (newAssetsCount == 0) {
_log.fine( _log.fine("No new assets found despite album having changes. Proceeding to full sync for ${dbAlbum.name}");
"No new assets found despite album having changes. Proceeding to full sync for ${dbAlbum.name}",
);
return false; return false;
} }
@@ -207,10 +189,7 @@ class LocalSyncService {
return false; return false;
} }
final newAssets = await _nativeSyncApi.getAssetsForAlbum( final newAssets = await _nativeSyncApi.getAssetsForAlbum(deviceAlbum.id, updatedTimeCond: updatedTime);
deviceAlbum.id,
updatedTimeCond: updatedTime,
);
await _localAlbumRepository.upsert( await _localAlbumRepository.upsert(
deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection), deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection),
@@ -230,18 +209,12 @@ class LocalSyncService {
Future<bool> fullDiff(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async { Future<bool> fullDiff(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async {
try { try {
final assetsInDevice = deviceAlbum.assetCount > 0 final assetsInDevice = deviceAlbum.assetCount > 0
? await _nativeSyncApi ? await _nativeSyncApi.getAssetsForAlbum(deviceAlbum.id).then((a) => a.toLocalAssets())
.getAssetsForAlbum(deviceAlbum.id)
.then((a) => a.toLocalAssets())
: <LocalAsset>[];
final assetsInDb = dbAlbum.assetCount > 0
? await _localAlbumRepository.getAssets(dbAlbum.id)
: <LocalAsset>[]; : <LocalAsset>[];
final assetsInDb = dbAlbum.assetCount > 0 ? await _localAlbumRepository.getAssets(dbAlbum.id) : <LocalAsset>[];
if (deviceAlbum.assetCount == 0) { if (deviceAlbum.assetCount == 0) {
_log.fine( _log.fine("Device album ${deviceAlbum.name} is empty. Removing assets from DB.");
"Device album ${deviceAlbum.name} is empty. Removing assets from DB.",
);
await _localAlbumRepository.upsert( await _localAlbumRepository.upsert(
deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection), deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection),
toDelete: assetsInDb.map((a) => a.id), toDelete: assetsInDb.map((a) => a.id),
@@ -249,18 +222,11 @@ class LocalSyncService {
return true; return true;
} }
final updatedDeviceAlbum = deviceAlbum.copyWith( final updatedDeviceAlbum = deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection);
backupSelection: dbAlbum.backupSelection,
);
if (dbAlbum.assetCount == 0) { if (dbAlbum.assetCount == 0) {
_log.fine( _log.fine("Device album ${deviceAlbum.name} is empty. Adding assets to DB.");
"Device album ${deviceAlbum.name} is empty. Adding assets to DB.", await _localAlbumRepository.upsert(updatedDeviceAlbum, toUpsert: assetsInDevice);
);
await _localAlbumRepository.upsert(
updatedDeviceAlbum,
toUpsert: assetsInDevice,
);
return true; return true;
} }
@@ -292,18 +258,12 @@ class LocalSyncService {
); );
if (assetsToUpsert.isEmpty && assetsToDelete.isEmpty) { if (assetsToUpsert.isEmpty && assetsToDelete.isEmpty) {
_log.fine( _log.fine("No asset changes detected in album ${deviceAlbum.name}. Updating metadata.");
"No asset changes detected in album ${deviceAlbum.name}. Updating metadata.",
);
_localAlbumRepository.upsert(updatedDeviceAlbum); _localAlbumRepository.upsert(updatedDeviceAlbum);
return true; return true;
} }
await _localAlbumRepository.upsert( await _localAlbumRepository.upsert(updatedDeviceAlbum, toUpsert: assetsToUpsert, toDelete: assetsToDelete);
updatedDeviceAlbum,
toUpsert: assetsToUpsert,
toDelete: assetsToDelete,
);
return true; return true;
} catch (e, s) { } catch (e, s) {
@@ -321,9 +281,7 @@ class LocalSyncService {
} }
bool _albumsEqual(LocalAlbum a, LocalAlbum b) { bool _albumsEqual(LocalAlbum a, LocalAlbum b) {
return a.name == b.name && return a.name == b.name && a.assetCount == b.assetCount && a.updatedAt.isAtSameMomentAs(b.updatedAt);
a.assetCount == b.assetCount &&
a.updatedAt.isAtSameMomentAs(b.updatedAt);
} }
} }
@@ -333,9 +291,7 @@ extension on Iterable<PlatformAlbum> {
(e) => LocalAlbum( (e) => LocalAlbum(
id: e.id, id: e.id,
name: e.name, name: e.name,
updatedAt: e.updatedAt == null updatedAt: e.updatedAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
? DateTime.now()
: DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
assetCount: e.assetCount, assetCount: e.assetCount,
), ),
).toList(); ).toList();
@@ -350,16 +306,13 @@ extension on Iterable<PlatformAsset> {
name: e.name, name: e.name,
checksum: null, checksum: null,
type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.other, type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.other,
createdAt: e.createdAt == null createdAt: e.createdAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000),
? DateTime.now() updatedAt: e.updatedAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
: DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000),
updatedAt: e.updatedAt == null
? DateTime.now()
: DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
width: e.width, width: e.width,
height: e.height, height: e.height,
durationInSeconds: e.durationInSeconds, durationInSeconds: e.durationInSeconds,
orientation: e.orientation, orientation: e.orientation,
isFavorite: e.isFavorite,
), ),
).toList(); ).toList();
} }
+4 -14
View File
@@ -56,17 +56,12 @@ class LogService {
}) async { }) async {
final instance = LogService._(logRepository, storeRepository, shouldBuffer); final instance = LogService._(logRepository, storeRepository, shouldBuffer);
await logRepository.truncate(limit: kLogTruncateLimit); await logRepository.truncate(limit: kLogTruncateLimit);
final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ?? final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ?? LogLevel.info.index;
LogLevel.info.index;
Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO; Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO;
return instance; return instance;
} }
LogService._( LogService._(this._logRepository, this._storeRepository, this._shouldBuffer) {
this._logRepository,
this._storeRepository,
this._shouldBuffer,
) {
_logSubscription = Logger.root.onRecord.listen(_handleLogRecord); _logSubscription = Logger.root.onRecord.listen(_handleLogRecord);
} }
@@ -90,10 +85,7 @@ class LogService {
if (_shouldBuffer) { if (_shouldBuffer) {
_msgBuffer.add(record); _msgBuffer.add(record);
_flushTimer ??= Timer( _flushTimer ??= Timer(const Duration(seconds: 5), () => unawaited(flushBuffer()));
const Duration(seconds: 5),
() => unawaited(flushBuffer()),
);
} else { } else {
unawaited(_logRepository.insert(record)); unawaited(_logRepository.insert(record));
} }
@@ -146,9 +138,7 @@ class LoggerUnInitializedException implements Exception {
/// Log levels according to dart logging [Level] /// Log levels according to dart logging [Level]
extension LevelDomainToInfraExtension on Level { extension LevelDomainToInfraExtension on Level {
LogLevel toLogLevel() => LogLevel toLogLevel() => LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ?? LogLevel.info;
LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ??
LogLevel.info;
} }
extension on LogLevel { extension on LogLevel {
@@ -0,0 +1,23 @@
import 'package:immich_mobile/domain/models/map.model.dart';
import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
typedef MapMarkerSource = Future<List<Marker>> Function(LatLngBounds? bounds);
typedef MapQuery = ({MapMarkerSource markerSource});
class MapFactory {
final DriftMapRepository _mapRepository;
const MapFactory({required DriftMapRepository mapRepository}) : _mapRepository = mapRepository;
MapService remote(String ownerId) => MapService(_mapRepository.remote(ownerId));
}
class MapService {
final MapMarkerSource _markerSource;
MapService(MapQuery query) : _markerSource = query.markerSource;
Future<List<Marker>> Function(LatLngBounds? bounds) get getMarkers => _markerSource;
}
@@ -13,6 +13,10 @@ class DriftMemoryService {
return _repository.getAll(ownerId); return _repository.getAll(ownerId);
} }
Future<DriftMemory?> get(String memoryId) {
return _repository.get(memoryId);
}
Future<int> getCount() { Future<int> getCount() {
return _repository.getCount(); return _repository.getCount();
} }
@@ -7,10 +7,7 @@ class DriftPartnerService {
final DriftPartnerRepository _driftPartnerRepository; final DriftPartnerRepository _driftPartnerRepository;
final PartnerApiRepository _partnerApiRepository; final PartnerApiRepository _partnerApiRepository;
const DriftPartnerService( const DriftPartnerService(this._driftPartnerRepository, this._partnerApiRepository);
this._driftPartnerRepository,
this._partnerApiRepository,
);
Future<List<PartnerUserDto>> getSharedWith(String userId) { Future<List<PartnerUserDto>> getSharedWith(String userId) {
return _driftPartnerRepository.getSharedWith(userId); return _driftPartnerRepository.getSharedWith(userId);
@@ -20,13 +17,9 @@ class DriftPartnerService {
return _driftPartnerRepository.getSharedBy(userId); return _driftPartnerRepository.getSharedBy(userId);
} }
Future<List<PartnerUserDto>> getAvailablePartners( Future<List<PartnerUserDto>> getAvailablePartners(String currentUserId) async {
String currentUserId, final otherUsers = await _driftPartnerRepository.getAvailablePartners(currentUserId);
) async { final currentPartners = await _driftPartnerRepository.getSharedBy(currentUserId);
final otherUsers =
await _driftPartnerRepository.getAvailablePartners(currentUserId);
final currentPartners =
await _driftPartnerRepository.getSharedBy(currentUserId);
final available = otherUsers.where((user) { final available = otherUsers.where((user) {
return !currentPartners.any((partner) => partner.id == user.id); return !currentPartners.any((partner) => partner.id == user.id);
}).toList(); }).toList();
@@ -41,10 +34,7 @@ class DriftPartnerService {
return; return;
} }
await _partnerApiRepository.update( await _partnerApiRepository.update(partnerId, inTimeline: !partner.inTimeline);
partnerId,
inTimeline: !partner.inTimeline,
);
await _driftPartnerRepository.toggleShowInTimeline(partner, userId); await _driftPartnerRepository.toggleShowInTimeline(partner, userId);
} }
@@ -0,0 +1,30 @@
import 'dart:async';
import 'package:immich_mobile/domain/models/person.model.dart';
import 'package:immich_mobile/infrastructure/repositories/people.repository.dart';
import 'package:immich_mobile/repositories/person_api.repository.dart';
class DriftPeopleService {
final DriftPeopleRepository _repository;
final PersonApiRepository _personApiRepository;
const DriftPeopleService(this._repository, this._personApiRepository);
Future<List<DriftPerson>> getAssetPeople(String assetId) {
return _repository.getAssetPeople(assetId);
}
Future<List<DriftPerson>> getAllPeople() {
return _repository.getAllPeople();
}
Future<int> updateName(String personId, String name) async {
await _personApiRepository.update(personId, name: name);
return _repository.updateName(personId, name);
}
Future<int> updateBrithday(String personId, DateTime birthday) async {
await _personApiRepository.update(personId, birthday: birthday);
return _repository.updateBirthday(personId, birthday);
}
}
@@ -22,11 +22,11 @@ class RemoteAlbumService {
return _repository.getAll(); return _repository.getAll();
} }
List<RemoteAlbum> sortAlbums( Future<RemoteAlbum?> get(String albumId) {
List<RemoteAlbum> albums, return _repository.get(albumId);
RemoteAlbumSortMode sortMode, { }
bool isReverse = false,
}) { List<RemoteAlbum> sortAlbums(List<RemoteAlbum> albums, RemoteAlbumSortMode sortMode, {bool isReverse = false}) {
return sortMode.sortFn(albums, isReverse); return sortMode.sortFn(albums, isReverse);
} }
@@ -44,8 +44,7 @@ class RemoteAlbumService {
filtered = filtered filtered = filtered
.where( .where(
(album) => (album) =>
album.name.toLowerCase().contains(lowerQuery) || album.name.toLowerCase().contains(lowerQuery) || album.description.toLowerCase().contains(lowerQuery),
album.description.toLowerCase().contains(lowerQuery),
) )
.toList(); .toList();
} }
@@ -53,12 +52,10 @@ class RemoteAlbumService {
if (userId != null) { if (userId != null) {
switch (filterMode) { switch (filterMode) {
case QuickFilterMode.myAlbums: case QuickFilterMode.myAlbums:
filtered = filtered = filtered.where((album) => album.ownerId == userId).toList();
filtered.where((album) => album.ownerId == userId).toList();
break; break;
case QuickFilterMode.sharedWithMe: case QuickFilterMode.sharedWithMe:
filtered = filtered = filtered.where((album) => album.ownerId != userId).toList();
filtered.where((album) => album.ownerId != userId).toList();
break; break;
case QuickFilterMode.all: case QuickFilterMode.all:
break; break;
@@ -68,16 +65,8 @@ class RemoteAlbumService {
return filtered; return filtered;
} }
Future<RemoteAlbum> createAlbum({ Future<RemoteAlbum> createAlbum({required String title, required List<String> assetIds, String? description}) async {
required String title, final album = await _albumApiRepository.createDriftAlbum(title, description: description, assetIds: assetIds);
required List<String> assetIds,
String? description,
}) async {
final album = await _albumApiRepository.createDriftAlbum(
title,
description: description,
assetIds: assetIds,
);
await _repository.create(album, assetIds); await _repository.create(album, assetIds);
@@ -119,14 +108,8 @@ class RemoteAlbumService {
return _repository.getAssets(albumId); return _repository.getAssets(albumId);
} }
Future<int> addAssets({ Future<int> addAssets({required String albumId, required List<String> assetIds}) async {
required String albumId, final album = await _albumApiRepository.addAssets(albumId, assetIds);
required List<String> assetIds,
}) async {
final album = await _albumApiRepository.addAssets(
albumId,
assetIds,
);
await _repository.addAssets(albumId, album.added); await _repository.addAssets(albumId, album.added);
@@ -139,10 +122,7 @@ class RemoteAlbumService {
await _repository.deleteAlbum(albumId); await _repository.deleteAlbum(albumId);
} }
Future<void> addUsers({ Future<void> addUsers({required String albumId, required List<String> userIds}) async {
required String albumId,
required List<String> userIds,
}) async {
await _albumApiRepository.addUsers(albumId, userIds); await _albumApiRepository.addUsers(albumId, userIds);
return _repository.addUsers(albumId, userIds); return _repository.addUsers(albumId, userIds);
@@ -83,10 +83,10 @@ extension on AssetResponseDto {
extension on AssetTypeEnum { extension on AssetTypeEnum {
AssetType toAssetType() => switch (this) { AssetType toAssetType() => switch (this) {
AssetTypeEnum.IMAGE => AssetType.image, AssetTypeEnum.IMAGE => AssetType.image,
AssetTypeEnum.VIDEO => AssetType.video, AssetTypeEnum.VIDEO => AssetType.video,
AssetTypeEnum.AUDIO => AssetType.audio, AssetTypeEnum.AUDIO => AssetType.audio,
AssetTypeEnum.OTHER => AssetType.other, AssetTypeEnum.OTHER => AssetType.other,
_ => throw Exception('Unknown AssetType value: $this'), _ => throw Exception('Unknown AssetType value: $this'),
}; };
} }
@@ -9,16 +9,11 @@ final AppSetting = SettingsService(storeService: StoreService.I);
class SettingsService { class SettingsService {
final StoreService _storeService; final StoreService _storeService;
const SettingsService({required StoreService storeService}) const SettingsService({required StoreService storeService}) : _storeService = storeService;
: _storeService = storeService;
T get<T>(Setting<T> setting) => T get<T>(Setting<T> setting) => _storeService.get(setting.storeKey, setting.defaultValue);
_storeService.get(setting.storeKey, setting.defaultValue);
Future<void> set<T>(Setting<T> setting, T value) => Future<void> set<T>(Setting<T> setting, T value) => _storeService.put(setting.storeKey, value);
_storeService.put(setting.storeKey, value);
Stream<T> watch<T>(Setting<T> setting) => _storeService Stream<T> watch<T>(Setting<T> setting) => _storeService.watch(setting.storeKey).map((v) => v ?? setting.defaultValue);
.watch(setting.storeKey)
.map((v) => v ?? setting.defaultValue);
} }
+6 -12
View File
@@ -12,8 +12,7 @@ class StoreService {
final Map<int, Object?> _cache = {}; final Map<int, Object?> _cache = {};
late final StreamSubscription<StoreDto> _storeUpdateSubscription; late final StreamSubscription<StoreDto> _storeUpdateSubscription;
StoreService._({required IsarStoreRepository storeRepository}) StoreService._({required IsarStoreRepository storeRepository}) : _storeRepository = storeRepository;
: _storeRepository = storeRepository;
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider // TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
static StoreService? _instance; static StoreService? _instance;
@@ -25,16 +24,12 @@ class StoreService {
} }
// TODO: Replace the implementation with the one from create after removing the typedef // TODO: Replace the implementation with the one from create after removing the typedef
static Future<StoreService> init({ static Future<StoreService> init({required IsarStoreRepository storeRepository}) async {
required IsarStoreRepository storeRepository,
}) async {
_instance ??= await create(storeRepository: storeRepository); _instance ??= await create(storeRepository: storeRepository);
return _instance!; return _instance!;
} }
static Future<StoreService> create({ static Future<StoreService> create({required IsarStoreRepository storeRepository}) async {
required IsarStoreRepository storeRepository,
}) async {
final instance = StoreService._(storeRepository: storeRepository); final instance = StoreService._(storeRepository: storeRepository);
await instance._populateCache(); await instance._populateCache();
instance._storeUpdateSubscription = instance._listenForChange(); instance._storeUpdateSubscription = instance._listenForChange();
@@ -48,10 +43,9 @@ class StoreService {
} }
} }
StreamSubscription<StoreDto> _listenForChange() => StreamSubscription<StoreDto> _listenForChange() => _storeRepository.watchAll().listen((event) {
_storeRepository.watchAll().listen((event) { _cache[event.key.id] = event.value;
_cache[event.key.id] = event.value; });
});
/// Disposes the store and cancels the subscription. To reuse the store call init() again /// Disposes the store and cancels the subscription. To reuse the store call init() again
void dispose() async { void dispose() async {
@@ -18,14 +18,14 @@ class SyncStreamService {
required SyncApiRepository syncApiRepository, required SyncApiRepository syncApiRepository,
required SyncStreamRepository syncStreamRepository, required SyncStreamRepository syncStreamRepository,
bool Function()? cancelChecker, bool Function()? cancelChecker,
}) : _syncApiRepository = syncApiRepository, }) : _syncApiRepository = syncApiRepository,
_syncStreamRepository = syncStreamRepository, _syncStreamRepository = syncStreamRepository,
_cancelChecker = cancelChecker; _cancelChecker = cancelChecker;
bool get isCancelled => _cancelChecker?.call() ?? false; bool get isCancelled => _cancelChecker?.call() ?? false;
Future<void> sync() { Future<void> sync() {
_logger.info("Remote sync request for userr"); _logger.info("Remote sync request for user");
DLog.log("Remote sync request for user"); DLog.log("Remote sync request for user");
// Start the sync stream and handle events // Start the sync stream and handle events
return _syncApiRepository.streamChanges(_handleEvents); return _syncApiRepository.streamChanges(_handleEvents);
@@ -34,9 +34,7 @@ class SyncStreamService {
Future<void> handleWsAssetUploadReadyV1Batch(List<dynamic> batchData) async { Future<void> handleWsAssetUploadReadyV1Batch(List<dynamic> batchData) async {
if (batchData.isEmpty) return; if (batchData.isEmpty) return;
_logger.info( _logger.info('Processing batch of ${batchData.length} AssetUploadReadyV1 events');
'Processing batch of ${batchData.length} AssetUploadReadyV1 events',
);
final List<SyncAssetV1> assets = []; final List<SyncAssetV1> assets = [];
final List<SyncAssetExifV1> exifs = []; final List<SyncAssetExifV1> exifs = [];
@@ -65,22 +63,12 @@ class SyncStreamService {
} }
if (assets.isNotEmpty && exifs.isNotEmpty) { if (assets.isNotEmpty && exifs.isNotEmpty) {
await _syncStreamRepository.updateAssetsV1( await _syncStreamRepository.updateAssetsV1(assets, debugLabel: 'websocket-batch');
assets, await _syncStreamRepository.updateAssetsExifV1(exifs, debugLabel: 'websocket-batch');
debugLabel: 'websocket-batch',
);
await _syncStreamRepository.updateAssetsExifV1(
exifs,
debugLabel: 'websocket-batch',
);
_logger.info('Successfully processed ${assets.length} assets in batch'); _logger.info('Successfully processed ${assets.length} assets in batch');
} }
} catch (error, stackTrace) { } catch (error, stackTrace) {
_logger.severe( _logger.severe("Error processing AssetUploadReadyV1 websocket batch events", error, stackTrace);
"Error processing AssetUploadReadyV1 websocket batch events",
error,
stackTrace,
);
} }
} }
@@ -114,10 +102,7 @@ class SyncStreamService {
batch.clear(); batch.clear();
} }
Future<void> _handleSyncData( Future<void> _handleSyncData(SyncEntityType type, Iterable<Object> data) async {
SyncEntityType type,
Iterable<Object> data,
) async {
_logger.fine("Processing sync data for $type of length ${data.length}"); _logger.fine("Processing sync data for $type of length ${data.length}");
switch (type) { switch (type) {
case SyncEntityType.userV1: case SyncEntityType.userV1:
@@ -135,30 +120,15 @@ class SyncStreamService {
case SyncEntityType.assetExifV1: case SyncEntityType.assetExifV1:
return _syncStreamRepository.updateAssetsExifV1(data.cast()); return _syncStreamRepository.updateAssetsExifV1(data.cast());
case SyncEntityType.partnerAssetV1: case SyncEntityType.partnerAssetV1:
return _syncStreamRepository.updateAssetsV1( return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'partner');
data.cast(),
debugLabel: 'partner',
);
case SyncEntityType.partnerAssetBackfillV1: case SyncEntityType.partnerAssetBackfillV1:
return _syncStreamRepository.updateAssetsV1( return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'partner backfill');
data.cast(),
debugLabel: 'partner backfill',
);
case SyncEntityType.partnerAssetDeleteV1: case SyncEntityType.partnerAssetDeleteV1:
return _syncStreamRepository.deleteAssetsV1( return _syncStreamRepository.deleteAssetsV1(data.cast(), debugLabel: "partner");
data.cast(),
debugLabel: "partner",
);
case SyncEntityType.partnerAssetExifV1: case SyncEntityType.partnerAssetExifV1:
return _syncStreamRepository.updateAssetsExifV1( return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'partner');
data.cast(),
debugLabel: 'partner',
);
case SyncEntityType.partnerAssetExifBackfillV1: case SyncEntityType.partnerAssetExifBackfillV1:
return _syncStreamRepository.updateAssetsExifV1( return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'partner backfill');
data.cast(),
debugLabel: 'partner backfill',
);
case SyncEntityType.albumV1: case SyncEntityType.albumV1:
return _syncStreamRepository.updateAlbumsV1(data.cast()); return _syncStreamRepository.updateAlbumsV1(data.cast());
case SyncEntityType.albumDeleteV1: case SyncEntityType.albumDeleteV1:
@@ -166,39 +136,21 @@ class SyncStreamService {
case SyncEntityType.albumUserV1: case SyncEntityType.albumUserV1:
return _syncStreamRepository.updateAlbumUsersV1(data.cast()); return _syncStreamRepository.updateAlbumUsersV1(data.cast());
case SyncEntityType.albumUserBackfillV1: case SyncEntityType.albumUserBackfillV1:
return _syncStreamRepository.updateAlbumUsersV1( return _syncStreamRepository.updateAlbumUsersV1(data.cast(), debugLabel: 'backfill');
data.cast(),
debugLabel: 'backfill',
);
case SyncEntityType.albumUserDeleteV1: case SyncEntityType.albumUserDeleteV1:
return _syncStreamRepository.deleteAlbumUsersV1(data.cast()); return _syncStreamRepository.deleteAlbumUsersV1(data.cast());
case SyncEntityType.albumAssetV1: case SyncEntityType.albumAssetV1:
return _syncStreamRepository.updateAssetsV1( return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'album');
data.cast(),
debugLabel: 'album',
);
case SyncEntityType.albumAssetBackfillV1: case SyncEntityType.albumAssetBackfillV1:
return _syncStreamRepository.updateAssetsV1( return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'album backfill');
data.cast(),
debugLabel: 'album backfill',
);
case SyncEntityType.albumAssetExifV1: case SyncEntityType.albumAssetExifV1:
return _syncStreamRepository.updateAssetsExifV1( return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'album');
data.cast(),
debugLabel: 'album',
);
case SyncEntityType.albumAssetExifBackfillV1: case SyncEntityType.albumAssetExifBackfillV1:
return _syncStreamRepository.updateAssetsExifV1( return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'album backfill');
data.cast(),
debugLabel: 'album backfill',
);
case SyncEntityType.albumToAssetV1: case SyncEntityType.albumToAssetV1:
return _syncStreamRepository.updateAlbumToAssetsV1(data.cast()); return _syncStreamRepository.updateAlbumToAssetsV1(data.cast());
case SyncEntityType.albumToAssetBackfillV1: case SyncEntityType.albumToAssetBackfillV1:
return _syncStreamRepository.updateAlbumToAssetsV1( return _syncStreamRepository.updateAlbumToAssetsV1(data.cast(), debugLabel: 'backfill');
data.cast(),
debugLabel: 'backfill',
);
case SyncEntityType.albumToAssetDeleteV1: case SyncEntityType.albumToAssetDeleteV1:
return _syncStreamRepository.deleteAlbumToAssetsV1(data.cast()); return _syncStreamRepository.deleteAlbumToAssetsV1(data.cast());
// No-op. SyncAckV1 entities are checkpoints in the sync stream // No-op. SyncAckV1 entities are checkpoints in the sync stream
@@ -218,28 +170,15 @@ class SyncStreamService {
case SyncEntityType.stackDeleteV1: case SyncEntityType.stackDeleteV1:
return _syncStreamRepository.deleteStacksV1(data.cast()); return _syncStreamRepository.deleteStacksV1(data.cast());
case SyncEntityType.partnerStackV1: case SyncEntityType.partnerStackV1:
return _syncStreamRepository.updateStacksV1( return _syncStreamRepository.updateStacksV1(data.cast(), debugLabel: 'partner');
data.cast(),
debugLabel: 'partner',
);
case SyncEntityType.partnerStackBackfillV1: case SyncEntityType.partnerStackBackfillV1:
return _syncStreamRepository.updateStacksV1( return _syncStreamRepository.updateStacksV1(data.cast(), debugLabel: 'partner backfill');
data.cast(),
debugLabel: 'partner backfill',
);
case SyncEntityType.partnerStackDeleteV1: case SyncEntityType.partnerStackDeleteV1:
return _syncStreamRepository.deleteStacksV1( return _syncStreamRepository.deleteStacksV1(data.cast(), debugLabel: 'partner');
data.cast(),
debugLabel: 'partner',
);
case SyncEntityType.userMetadataV1: case SyncEntityType.userMetadataV1:
return _syncStreamRepository.updateUserMetadatasV1( return _syncStreamRepository.updateUserMetadatasV1(data.cast());
data.cast(),
);
case SyncEntityType.userMetadataDeleteV1: case SyncEntityType.userMetadataDeleteV1:
return _syncStreamRepository.deleteUserMetadatasV1( return _syncStreamRepository.deleteUserMetadatasV1(data.cast());
data.cast(),
);
case SyncEntityType.personV1: case SyncEntityType.personV1:
return _syncStreamRepository.updatePeopleV1(data.cast()); return _syncStreamRepository.updatePeopleV1(data.cast());
case SyncEntityType.personDeleteV1: case SyncEntityType.personDeleteV1:
@@ -10,34 +10,29 @@ import 'package:immich_mobile/domain/services/setting.service.dart';
import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/domain/utils/event_stream.dart';
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
import 'package:immich_mobile/utils/async_mutex.dart'; import 'package:immich_mobile/utils/async_mutex.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
typedef TimelineAssetSource = Future<List<BaseAsset>> Function( typedef TimelineAssetSource = Future<List<BaseAsset>> Function(int index, int count);
int index,
int count,
);
typedef TimelineBucketSource = Stream<List<Bucket>> Function(); typedef TimelineBucketSource = Stream<List<Bucket>> Function();
typedef TimelineQuery = ({ typedef TimelineQuery = ({TimelineAssetSource assetSource, TimelineBucketSource bucketSource});
TimelineAssetSource assetSource,
TimelineBucketSource bucketSource,
});
class TimelineFactory { class TimelineFactory {
final DriftTimelineRepository _timelineRepository; final DriftTimelineRepository _timelineRepository;
final SettingsService _settingsService; final SettingsService _settingsService;
const TimelineFactory({ const TimelineFactory({required DriftTimelineRepository timelineRepository, required SettingsService settingsService})
required DriftTimelineRepository timelineRepository, : _timelineRepository = timelineRepository,
required SettingsService settingsService, _settingsService = settingsService;
}) : _timelineRepository = timelineRepository,
_settingsService = settingsService;
GroupAssetsBy get groupBy => GroupAssetsBy get groupBy {
GroupAssetsBy.values[_settingsService.get(Setting.groupAssetsBy)]; final group = GroupAssetsBy.values[_settingsService.get(Setting.groupAssetsBy)];
// We do not support auto grouping in the new timeline yet, fallback to day grouping
return group == GroupAssetsBy.auto ? GroupAssetsBy.day : group;
}
TimelineService main(List<String> timelineUsers) => TimelineService main(List<String> timelineUsers) => TimelineService(_timelineRepository.main(timelineUsers, groupBy));
TimelineService(_timelineRepository.main(timelineUsers, groupBy));
TimelineService localAlbum({required String albumId}) => TimelineService localAlbum({required String albumId}) =>
TimelineService(_timelineRepository.localAlbum(albumId, groupBy)); TimelineService(_timelineRepository.localAlbum(albumId, groupBy));
@@ -45,29 +40,26 @@ class TimelineFactory {
TimelineService remoteAlbum({required String albumId}) => TimelineService remoteAlbum({required String albumId}) =>
TimelineService(_timelineRepository.remoteAlbum(albumId, groupBy)); TimelineService(_timelineRepository.remoteAlbum(albumId, groupBy));
TimelineService remoteAssets(String userId) => TimelineService remoteAssets(String userId) => TimelineService(_timelineRepository.remote(userId, groupBy));
TimelineService(_timelineRepository.remote(userId, groupBy));
TimelineService favorite(String userId) => TimelineService favorite(String userId) => TimelineService(_timelineRepository.favorite(userId, groupBy));
TimelineService(_timelineRepository.favorite(userId, groupBy));
TimelineService trash(String userId) => TimelineService trash(String userId) => TimelineService(_timelineRepository.trash(userId, groupBy));
TimelineService(_timelineRepository.trash(userId, groupBy));
TimelineService archive(String userId) => TimelineService archive(String userId) => TimelineService(_timelineRepository.archived(userId, groupBy));
TimelineService(_timelineRepository.archived(userId, groupBy));
TimelineService lockedFolder(String userId) => TimelineService lockedFolder(String userId) => TimelineService(_timelineRepository.locked(userId, groupBy));
TimelineService(_timelineRepository.locked(userId, groupBy));
TimelineService video(String userId) => TimelineService video(String userId) => TimelineService(_timelineRepository.video(userId, groupBy));
TimelineService(_timelineRepository.video(userId, groupBy));
TimelineService place(String place) => TimelineService place(String place) => TimelineService(_timelineRepository.place(place, groupBy));
TimelineService(_timelineRepository.place(place, groupBy));
TimelineService fromAssets(List<BaseAsset> assets) => TimelineService person(String userId, String personId) =>
TimelineService(_timelineRepository.fromAssets(assets)); TimelineService(_timelineRepository.person(userId, personId, groupBy));
TimelineService fromAssets(List<BaseAsset> assets) => TimelineService(_timelineRepository.fromAssets(assets));
TimelineService map(LatLngBounds bounds) => TimelineService(_timelineRepository.map(bounds, groupBy));
} }
class TimelineService { class TimelineService {
@@ -81,21 +73,14 @@ class TimelineService {
int _totalAssets = 0; int _totalAssets = 0;
int get totalAssets => _totalAssets; int get totalAssets => _totalAssets;
TimelineService(TimelineQuery query) TimelineService(TimelineQuery query) : this._(assetSource: query.assetSource, bucketSource: query.bucketSource);
: this._(
assetSource: query.assetSource,
bucketSource: query.bucketSource,
);
TimelineService._({ TimelineService._({required TimelineAssetSource assetSource, required TimelineBucketSource bucketSource})
required TimelineAssetSource assetSource, : _assetSource = assetSource,
required TimelineBucketSource bucketSource, _bucketSource = bucketSource {
}) : _assetSource = assetSource,
_bucketSource = bucketSource {
_bucketSubscription = _bucketSource().listen((buckets) { _bucketSubscription = _bucketSource().listen((buckets) {
_mutex.run(() async { _mutex.run(() async {
final totalAssets = final totalAssets = buckets.fold<int>(0, (acc, bucket) => acc + bucket.assetCount);
buckets.fold<int>(0, (acc, bucket) => acc + bucket.assetCount);
if (totalAssets == 0) { if (totalAssets == 0) {
_bufferOffset = 0; _bufferOffset = 0;
@@ -110,10 +95,7 @@ class TimelineService {
count = kTimelineAssetLoadBatchSize; count = kTimelineAssetLoadBatchSize;
} else { } else {
offset = _bufferOffset; offset = _bufferOffset;
count = math.min( count = math.min(_buffer.length, totalAssets - _bufferOffset);
_buffer.length,
totalAssets - _bufferOffset,
);
} }
_buffer = await _assetSource(offset, count); _buffer = await _assetSource(offset, count);
_bufferOffset = offset; _bufferOffset = offset;
@@ -128,8 +110,7 @@ class TimelineService {
Stream<List<Bucket>> Function() get watchBuckets => _bucketSource; Stream<List<Bucket>> Function() get watchBuckets => _bucketSource;
Future<List<BaseAsset>> loadAssets(int index, int count) => Future<List<BaseAsset>> loadAssets(int index, int count) => _mutex.run(() => _loadAssets(index, count));
_mutex.run(() => _loadAssets(index, count));
Future<List<BaseAsset>> _loadAssets(int index, int count) async { Future<List<BaseAsset>> _loadAssets(int index, int count) async {
if (hasRange(index, count)) { if (hasRange(index, count)) {
@@ -142,10 +123,7 @@ class TimelineService {
// make sure to load a meaningful amount of data (and not only the requested slice) // make sure to load a meaningful amount of data (and not only the requested slice)
// otherwise, each call to [loadAssets] would result in DB call trashing performance // otherwise, each call to [loadAssets] would result in DB call trashing performance
// fills small requests to [kTimelineAssetLoadBatchSize], adds some legroom into the opposite scroll direction for large requests // fills small requests to [kTimelineAssetLoadBatchSize], adds some legroom into the opposite scroll direction for large requests
final len = math.max( final len = math.max(kTimelineAssetLoadBatchSize, count + kTimelineAssetLoadOppositeSize);
kTimelineAssetLoadBatchSize,
count + kTimelineAssetLoadOppositeSize,
);
// when scrolling forward, start shortly before the requested offset // when scrolling forward, start shortly before the requested offset
// when scrolling backward, end shortly after the requested offset to guard against the user scrolling // when scrolling backward, end shortly after the requested offset to guard against the user scrolling
// in the other direction a tiny bit resulting in another required load from the DB // in the other direction a tiny bit resulting in another required load from the DB
@@ -178,11 +156,9 @@ class TimelineService {
} }
// Pre-cache assets around the given index for asset viewer // Pre-cache assets around the given index for asset viewer
Future<void> preCacheAssets(int index) => Future<void> preCacheAssets(int index) => _mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index)));
_mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index)));
BaseAsset getRandomAsset() => BaseAsset getRandomAsset() => _buffer.elementAt(math.Random().nextInt(_buffer.length));
_buffer.elementAt(math.Random().nextInt(_buffer.length));
BaseAsset getAsset(int index) { BaseAsset getAsset(int index) {
if (!hasRange(index, 1)) { if (!hasRange(index, 1)) {
+4 -7
View File
@@ -18,9 +18,9 @@ class UserService {
required IsarUserRepository isarUserRepository, required IsarUserRepository isarUserRepository,
required UserApiRepository userApiRepository, required UserApiRepository userApiRepository,
required StoreService storeService, required StoreService storeService,
}) : _isarUserRepository = isarUserRepository, }) : _isarUserRepository = isarUserRepository,
_userApiRepository = userApiRepository, _userApiRepository = userApiRepository,
_storeService = storeService; _storeService = storeService;
UserDto getMyUser() { UserDto getMyUser() {
return _storeService.get(StoreKey.currentUser); return _storeService.get(StoreKey.currentUser);
@@ -44,10 +44,7 @@ class UserService {
Future<String?> createProfileImage(String name, Uint8List image) async { Future<String?> createProfileImage(String name, Uint8List image) async {
try { try {
final path = await _userApiRepository.createProfileImage( final path = await _userApiRepository.createProfileImage(name: name, data: image);
name: name,
data: image,
);
final updatedUser = getMyUser().copyWith(profileImagePath: path); final updatedUser = getMyUser().copyWith(profileImagePath: path);
await _storeService.put(StoreKey.currentUser, updatedUser); await _storeService.put(StoreKey.currentUser, updatedUser);
await _isarUserRepository.update(updatedUser); await _isarUserRepository.update(updatedUser);

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