Compare commits

...

120 Commits

Author SHA1 Message Date
midzelis
369e6de57b Rename things 2025-09-21 14:23:05 +00:00
midzelis
2accf351bd Search results use photostream 2025-09-21 02:24:29 +00:00
midzelis
10f599bee1 refactor(web): extract PhotostreamManager base class 2025-09-18 21:07:45 +00:00
midzelis
8d4978602b refactor(web): rename loadMonthGroup to loadSegment API 2025-09-18 21:07:45 +00:00
midzelis
3e9f713d81 refactor: new timeline component
- Create new timeline component (extracted from asset-gird) without removing old code
- Add timeline/, timeline/actions/, timeline/base-components/, and timeline/internal-components/ directories
- Copy needed components (delete-asset-dialog, scrubber, skeleton) to new locations
- Add new timeline components (base-timeline, base-timeline-viewer, timeline-month, etc.)
- Update timeline-util.ts with new functions (findMonthAtScrollPosition, formatGroupTitleFull)
- Add asset-viewer-actions and asset-viewer-and-actions components

This allows the timeline to exist alongside the current AssetGrid component.
2025-09-18 21:07:45 +00:00
Alex
e42886b767 fix: display thumbnail while scrubbing paused (#22164)
* fix: display thumbnail while scrubbing paused

* pr feedback

* pr feedback

* tune timeout
2025-09-18 20:59:58 +00:00
Alex
d36c26bf97 chore: refresh backup stats when entering backup page (#21977)
* chore: refresh backup stats when entering backup page

* check for success status

* remove logs

* remove sync remote when toggle the button

* show status immediately after navigating to screen

* pr feedback
2025-09-18 15:36:43 -05:00
Brandon Wees
dcbc266b83 chore: disable mise lockfile (#22182) 2025-09-18 15:44:33 -04:00
bo0tzz
c37d13691b feat: shared pre-job action (#20011) 2025-09-18 11:21:06 +02:00
Mert
9ae42106cc fix(mobile): stack row blocking gestures and not showing up (#21854) 2025-09-18 06:16:14 +00:00
Alex
28e9892ed3 fix: show thumbnail instantly when jumping to top of the page (#22163)
* fix: show thumbnail instantly when jumping to top of the page

* pr feedback
2025-09-18 05:26:39 +00:00
shenlong
532ec10d5f refactor: hashing service (#21997)
* download only backup selected assets

* android impl

* fix tests

* limit concurrent hashing to 16

* extension cleanup

* optimized hashing

* hash only selected albums

* remove concurrency limit

* address review comments

* log more info on failure

* add native cancellation

* small batch size on ios, large on android

* fix: get correct resources

* cleanup getResource

* ios better hash cancellation

* handle graceful cancellation android

* do not trigger multiple hashing ops

* ios: fix circular reference, improve cancellation

* kotlin: more cancellation checks

* no need to create result

* cancel previous task

* avoid race condition

* ensure cancellation gets called

* fix cancellation not happening

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-09-17 23:42:37 -05:00
Alex
2411bf8374 fix: asset viewer background isn't shown (#22161)
* fix: asset viewer background isn't shown

* pr feedback
2025-09-17 23:26:16 -05:00
Mert
0b60cc8965 fix(mobile): thumbnail shimmering effect (#22158)
full opacity
2025-09-17 22:29:37 -05:00
Jason Rasmussen
2d816e89ad refactor(web): prefer modal manager (#22152) 2025-09-17 23:23:42 +02:00
Jason Rasmussen
eee94207ce refactor(web): album users modal (#22153) 2025-09-17 17:04:54 -04:00
Jason Rasmussen
dfa38ec3ef fix(web): download panel (#22150) 2025-09-17 15:40:11 -05:00
Jason Rasmussen
edc0698e2a refactor: album edit modal (#22151) 2025-09-17 16:34:12 -04:00
shenlong
0e987352bb fix: do not migrate existing users (#22146)
fix: do not migrate if already on 15+

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-17 13:20:43 -05:00
Jason Rasmussen
98ea3847e5 refactor: server-about-modal (#22138)
* refactor: server-about-modal

* fix: bits-ui scroll lock cleanup
2025-09-17 16:23:23 +00:00
shenlong
53c67f4d71 fix: show delete on device when asset has a local match (#22143)
* fix: show delete on device when asset has a local match

* change test description

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-17 21:48:54 +05:30
Mert
20733bd7df fix(mobile): load original image (#22142)
load original image
2025-09-17 12:14:16 -04:00
Jason Rasmussen
11e72a0f35 refactor: text-primary (#22141) 2025-09-17 12:12:51 -04:00
Jason Rasmussen
53a6724039 refactor: hot module reload component (#22135) 2025-09-17 12:12:37 -04:00
Jason Rasmussen
0b20d1df9f feat(web): toggle theme shortcut (#22139) 2025-09-17 12:12:23 -04:00
Alex
6bb8903b05 chore: revert poll counts from DB rather than using callbacks from library (#22117) (#22140)
Revert "fix: poll counts from DB rather than using callbacks from library (#22117)"

This reverts commit 29fd981587.
2025-09-17 15:41:33 +00:00
Stewart Rand
26e0cb3eb4 fix: Refresh photo after updating featured photo (#21971)
fix: Refresh person photo after setting featured photo

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-09-17 10:22:26 -05:00
shenlong
a8f683ed15 chore(dep): bump flutter to 3.35.4 (#22129)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-17 14:58:35 +00:00
Viktor Mykhailiv
4dfa011eef fix: initial size of bottom sheet (#22085) 2025-09-17 14:41:44 +00:00
Viktor Mykhailiv
0c0bec6ae2 fix: display album image in selection mode (#22087)
* fix: display album image in selection mode

* fix: align MultiSelectStatusButton to display instead of back button in album

* small styling tweak

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-09-17 14:38:25 +00:00
shenlong
61c3f27fdc feat: add configurable backup on charging only and delay settings for android (#22114)
* feat: add configurable on charging only and delay

* Segmented and style the settings

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-09-17 14:13:49 +00:00
Alex
b2ca208dbb fix: ensure background worker is scheduled when the app is dismissed (#22032)
* fix: ensure background worker is scheduled when the app is dismissed

* remove logs

* fix: use native locks (#22081)

* fix: native locks

* use atomicints

* change count check

---------

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

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-17 09:11:55 -05:00
shenlong
2e945281fc fix: beta migration check (#22092)
fix: beta migration

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-17 08:45:04 -05:00
shenlong
9ac120c772 chore: add mobile codeowner (#22130)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-17 14:08:35 +02:00
Min Idzelis
e6e8ae7c74 chore: remove suppressed warnings (#22120)
chore: remove supressed warnings
2025-09-17 00:06:27 -04:00
shenlong
29fd981587 fix: poll counts from DB rather than using callbacks from library (#22117)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-16 21:13:34 -05:00
Mert
585b74f233 chore(deps): bump flutter to 3.35.3 (#22054)
* bump flutter to 3.35.3

* migrate deprecated code

* linting

* disable custom_lint in ci

* disable custom_lint
2025-09-16 21:10:01 -05:00
Mert
f118bb7e08 fix(mobile): prevent concurrent refresh and processing tasks (#22111)
* task semaphore

* always call setTaskCompleted
2025-09-16 18:06:19 -04:00
renovate[bot]
1710230d61 chore(deps): update dependency @types/nodemailer to v7 (#22047)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 22:17:03 +01:00
Jason Rasmussen
2012b07645 refactor: admin settings (#22109) 2025-09-16 17:15:57 -04:00
renovate[bot]
a88a9a7d5e chore(deps): update dependency @faker-js/faker to v10 (#21514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 21:13:09 +00:00
renovate[bot]
ae539dfdf3 chore(deps): update terraform cloudflare to v4.52.5 (#22044)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 22:01:44 +01:00
renovate[bot]
69bb8d834f chore(deps): update github-actions (#22041)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 21:59:58 +01:00
Jason Rasmussen
9693d07a8b refactor: components (#22106) 2025-09-16 16:58:47 -04:00
Jason Rasmussen
453b30069d chore: discord from simple icons (#22104) 2025-09-16 16:33:56 -04:00
Jason Rasmussen
c9daefccc4 refactor: loading spinner (#22103) 2025-09-16 16:22:13 -04:00
Jason Rasmussen
6ffd8e679e refactor: use immich/ui PasswordInput (#22099)
refactor: password-input
2025-09-16 16:09:09 -04:00
Daniel Dietzler
7fe2f19258 chore: migrate to UI lib icon (#22096) 2025-09-16 21:40:43 +02:00
Jason Rasmussen
dac545496e chore: bump immich/ui (#22100) 2025-09-16 15:39:56 -04:00
renovate[bot]
d5b112be53 chore(deps): update ghcr.io/immich-app/postgres:14-vectorchord0.3.0 docker digest to 11ced39 (#22037)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 21:38:14 +02:00
Jason Rasmussen
75322179fd refactor: more elements (#22095) 2025-09-16 15:01:23 -04:00
Jason Rasmussen
3f4b6a8e7c refactor: move more elements (#22093) 2025-09-16 14:47:38 -04:00
Jason Rasmussen
7ce1d73c20 refactor: move components/elements to elements/ (#22091) 2025-09-16 18:31:22 +00:00
Jason Rasmussen
2bf484c91c refactor: timeline components (#22089) 2025-09-16 14:01:12 -04:00
Alex
4e9bdd5e6c fix: storage indicator (#22077) 2025-09-16 12:46:48 -05:00
Jason Rasmussen
f05ef81c4f fix(web): issue with modal locking the page (#22079) 2025-09-16 12:46:09 -05:00
Jason Rasmussen
c21860fb97 refactor: rename timeline actions (#22086) 2025-09-16 13:37:01 -04:00
linux-universe
449368eee7 chore(docs): add an updated Podman/Quadlets community guide (#20744)
* chore(docs): update Podman/Quadlets instructions link to a more up to date repo

* Update community-guides.tsx: additional guide instead of replacing the other podman one

* fix community-guides.tsx: fixed podman handbook entry

* chore: linting

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-09-16 17:05:54 +00:00
Jason Rasmussen
31e098517d chore: rename asset-grid to timeline (#22084) 2025-09-16 13:05:09 -04:00
Jason Rasmussen
b9e2590752 chore: simplify (#22082) 2025-09-16 12:48:44 -04:00
Jason Rasmussen
41641ec000 chore: build sdk while server is starting (#22083) 2025-09-16 12:48:31 -04:00
Alex
8821c251c3 fix: navigate to time (#22078) 2025-09-16 11:40:31 -05:00
Jason Rasmussen
1d6b98ff86 chore: remove prepare-volumes (#22071) 2025-09-16 10:19:09 -04:00
bo0tzz
4d00261bc1 chore(mobile): translate missing strings (#22057) 2025-09-16 08:51:03 -05:00
Tom Laermans
df7ea4d8ea docs: add community immich-birthday and immich-stack projects (#21934) 2025-09-16 04:01:18 +00:00
bo0tzz
1e7cb1165f fix: add pnpm setup to fix-format worflow (#21805) 2025-09-15 23:57:58 -04:00
Alex
d9ef041b87 chore: remove beta wording and badges (#22040)
* chore: remove beta wordings and badges

* chore: remove beta wordings and badges
2025-09-15 22:55:29 -05:00
Alex
87a172ab0c fix: distance of segment label overlapsed scrubber label (#22043) 2025-09-15 22:55:07 -05:00
Jason Rasmussen
9e0553e0c4 fix(server): bulk edit rating (#21839) 2025-09-16 03:50:27 +00:00
uphillcheddar
a7addfece8 fix(oauth): omit blank pkce from url when not supported (#21976)
* fix(oauth): omit blank pkce from url when now pkce

* fix(oauth): use spread operator for pkce params

* chore: use first method

---------

Co-authored-by: Your Name <you@example.com>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2025-09-16 03:48:33 +00:00
renovate[bot]
fda215f97f chore(deps): update dependency vite to v7.1.5 [security] (#21783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 03:47:29 +00:00
Jason Rasmussen
5fad1fd899 chore: split Dockerfile (#22007) 2025-09-15 23:41:35 -04:00
Sergey Katsubo
880f2bc2c5 chore(docs): TypeORM error: force recommend v1.132.3 and avoid v1.136 (#22033)
* TypeORM error: force recommend v1.132.3 and avoid v1.136

* Add extra line break for clarity

* Fix formatting error: remove an asterisk

* chore: use admonitions

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2025-09-16 03:29:12 +00:00
Stewart Rand
0f79e0c38e fix: Use CSS for uppercase text (#22011) 2025-09-15 23:28:42 -04:00
renovate[bot]
5fb0afb0d0 chore(deps): update ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 docker digest to c44be5f (#22038)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 23:13:21 -04:00
renovate[bot]
4f4a50ac11 chore(deps): update dependency @types/node to ^22.18.1 (#22042)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 23:12:15 -04:00
Alex
3d883b27aa fix: sidebar link hightlight (#22035)
* fix: sidebar link hightlight

* check if current route start with href
2025-09-15 22:19:55 -04:00
Zack Pollard
01fddd58c6 chore: update ROCm image (#22034) 2025-09-15 20:42:17 -04:00
shenlong
81eb5ab40d fix: close menu anchor on navigation (#22021)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-15 15:05:22 -05:00
Zack Pollard
8d849d226d chore: remove workflows that are now applied org-wide (#22019) 2025-09-15 19:16:11 +01:00
Alex
a9b82a8e32 chore: post release tasks (#22014) 2025-09-15 18:08:25 +00:00
immich-tofu[bot]
cc9e07401f chore: modify .github/workflows/org-zizmor.yml 2025-09-15 17:59:16 +00:00
immich-tofu[bot]
9b5f3552c0 chore: modify .github/workflows/org-zizmor.yml 2025-09-15 17:47:59 +00:00
immich-tofu[bot]
a52a3247d7 chore: modify .github/workflows/org-zizmor.yml 2025-09-15 17:28:11 +00:00
immich-tofu[bot]
c86c957860 chore: modify .github/workflows/org-pr-require-conventional-commit.yml 2025-09-15 17:27:51 +00:00
immich-tofu[bot]
eb15a2725a chore: modify .github/workflows/org-checks.yml 2025-09-15 17:26:57 +00:00
Weblate (bot)
b394046d2a chore(web): update translations (#21842)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/be/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/eu/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/gl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/he/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/it/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ja/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lt/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lv/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/mr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pt/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ru/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sr_Latn/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sv/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/tr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/uk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: Abhijeet Bonde <abhijeetbonde19@gmail.com>
Co-authored-by: Adrián Nieto Rodríguez <adrian.nieto7@gmail.com>
Co-authored-by: Alexander Lohnes <alex.lohnes@googlemail.com>
Co-authored-by: Dawider10 <dawider110@gmail.com>
Co-authored-by: DevServs <bonov@mail.ru>
Co-authored-by: Jordy H <jordy@hoebergen.net>
Co-authored-by: Marcelo Popper Costa <marcelo_popper@hotmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Nuno Rodrigues <nunogand@gmail.com>
Co-authored-by: Pavlogal <pavledosen.p@gmail.com>
Co-authored-by: Pazystamas <pazystamas@gmail.com>
Co-authored-by: Phantom0174 <darrenhsiou@gmail.com>
Co-authored-by: PontusÖsterlindh <pontus@osterlindh.com>
Co-authored-by: Sergey Katsubo <skatsubo@gmail.com>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: TV Box <realceday.tvbox@gmail.com>
Co-authored-by: Taiki M <vexingly-many-mace@duck.com>
Co-authored-by: Urko Perez Azkarragaurizar <urkoperez16@gmail.com>
Co-authored-by: User 123456789 <user123456789@users.noreply.hosted.weblate.org>
Co-authored-by: Vegard Fladby <vegard@fladby.org>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: cube64 <204@tuta.io>
Co-authored-by: millallo <millallo@tiscali.it>
Co-authored-by: pyccl <changcongliang@163.com>
Co-authored-by: vzvl <lojewski.vitus@gmail.com>
2025-09-15 17:15:41 +00:00
github-actions
859b2451bb chore: version v1.142.1 2025-09-15 17:08:25 +00:00
Mert
b79a2eb6b9 chore(mobile): const platform checks (#21878)
* use `defaultTargetPlatform`

* extension

* formatting
2025-09-15 11:13:39 -04:00
Yaros
ee96b285f2 chore(mobile): minor changes to bottom sheet (#22008) 2025-09-15 10:09:27 -05:00
Alex
77340075f0 chore: making order of background tasks better (#21928)
* chore: making order of background tasks better

* chore: prevent action not running when returning from backup screen too soon after toggle backup
2025-09-15 10:07:41 -05:00
shenlong
5c06ec5e0b fix: move startInitialization to inside the doWork method (#21984)
fix: android background backup

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-15 10:06:30 -05:00
shenlong
dcee34095b fix: reset sqlite on beta migration (#20735)
reset sync stream on migration

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-14 16:30:25 -05:00
Alex
15f182902f fix: check if preferencesStore is defined (#21958) 2025-09-14 20:30:15 +00:00
shenlong
b26b452530 fix: do not listen for store updates in isolates (#21947)
* dispose store on isolate cleanup

* do not listen for store updates in isolates

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-09-14 14:50:17 -05:00
shenlong
2dcb32f7d0 chore: update background downloader (#21909)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-14 14:44:48 -05:00
Brandon Wees
27d2f3efe2 feat: disable snapping when a timeline has less than 12 months (#21649)
* feat: disable snapping when a timeline has less than 12 months

* fix: disable placeholders when not snapping

also moved month constant to constants.dart

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-09-14 19:24:52 +00:00
shenlong
d38468439b fix: complete does not destroy engine on close (#21943)
* fix: complete does not destroy engine on close

* reset flutterApi on cleanup

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-14 14:17:12 -05:00
Alex
0166e99d90 chore: remove main timeline query watch throttle (#21942) 2025-09-14 02:09:07 -05:00
Alex
71e33e35dc chore: check before sync linked albums from websocket events (#21941) 2025-09-14 02:08:41 -05:00
Mert
a122d4b969 fix(mobile): double hero animation (#21927)
fix double hero animation
2025-09-13 16:47:07 -05:00
shenlong
dad81af6e3 fix: show view in timeline from search page (#21873)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-12 22:44:31 -05:00
shenlong
ac6b42e1e8 fix: do not show stack action if there is only one selection (#21868)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-12 22:43:51 -05:00
Stewart Rand
4059638151 fix: context menu jank (#21844)
* Fix issue with context menu jank by only applying overflow styling when transition is complete

* Remove comment

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

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-09-12 22:43:22 -05:00
Stewart Rand
1823a28e59 chore: improve date text slide-in transition (#21879)
* Make date text slide-in transition smooth

* fix: lint

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-09-13 03:42:42 +00:00
Stewart Rand
b6bf1852cd fix: keep adequate space around page title (#21881)
Keep space around page title
2025-09-12 22:42:25 -05:00
Stewart Rand
cdc26f2c7b fix: z-index of top bar on show/hide people view (#21847)
Fix z-index of top bar on show/hide people view
2025-09-12 22:32:50 -05:00
Alex
913b3789cc chore: simplify timeline switcher toggle (#21864)
chore: timeline switcher option simplify
2025-09-12 22:32:15 -05:00
Stewart Rand
994a770921 chore: improve context button accessibility (#21876)
Make context menu button filled on album list and faces page
2025-09-12 22:31:52 -05:00
Mert
17bbcdf584 chore(mobile): add debugPrint lint rule (#21872)
* add lint rule

* update usages

* stragglers

* use dcm

* formatting

* test ci

* Revert "test ci"

This reverts commit 8f864c4e4d.

* revert whitespace change
2025-09-12 18:56:00 -04:00
bo0tzz
23aa661324 fix: use mdq image with jq (#21860) 2025-09-12 21:46:39 +02:00
Min Idzelis
a10a946d1a fix: let dev docker compose service runs as root (#21579) 2025-09-12 16:20:41 +01:00
Stewart Rand
04c9531624 fix: format point count numbers on map view (#21848)
Format numbers on map view
2025-09-12 07:20:05 +00:00
Alex
d84cc450f1 chore: post release tasks (#21834) 2025-09-11 15:15:10 -05:00
github-actions
4153848c68 chore: version v1.142.0 2025-09-11 19:39:05 +00:00
Jason Rasmussen
f29230c8a6 fix(web): handle buckets before year 1000 (#21832) 2025-09-11 14:36:16 -05:00
Weblate (bot)
03af60e8eb chore(web): update translations (#21814)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ja/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ru/
Translation: Immich/immich

Co-authored-by: DevServs <bonov@mail.ru>
Co-authored-by: Taiki M <vexingly-many-mace@duck.com>
2025-09-11 19:34:40 +00:00
bo0tzz
ae827e1406 fix: define call secrets in merge-translations (#21831) 2025-09-11 19:29:58 +00:00
shenlong
7893ac25fb fix: always use en locale for parsing timeline datetime (#21796)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-09-11 14:20:39 -05:00
Alex
42a03f2556 fix: concurrency issue (#21830) 2025-09-11 19:02:03 +00:00
501 changed files with 10098 additions and 5668 deletions

View File

@@ -12,7 +12,6 @@ services:
- server_node_modules:/workspaces/immich/server/node_modules
- web_node_modules:/workspaces/immich/web/node_modules
- ${UPLOAD_LOCATION}/photos:/data
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
- /etc/localtime:/etc/localtime:ro
database:

View File

@@ -8,8 +8,7 @@ services:
- IMMICH_SERVER_URL=http://127.0.0.1:2283/
volumes: !override
- ..:/workspaces/immich
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/data/upload
- ${UPLOAD_LOCATION:-upload-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data
- /etc/localtime:/etc/localtime:ro
- pnpm-store:/usr/src/app/.pnpm-store
- server-node_modules:/usr/src/app/server/node_modules
@@ -24,9 +23,6 @@ services:
- coverage:/usr/src/app/web/coverage
immich-web:
env_file: !reset []
init:
env_file: !reset []
command: sh -c 'find /data -maxdepth 1 ! -path "/data/postgres" -type d -exec chown ${UID:-1000}:${GID:-1000} {} + 2>/dev/null || true; for path in /usr/src/app/.pnpm-store /usr/src/app/server/node_modules /usr/src/app/server/dist /usr/src/app/.github/node_modules /usr/src/app/cli/node_modules /usr/src/app/docs/node_modules /usr/src/app/e2e/node_modules /usr/src/app/open-api/typescript-sdk/node_modules /usr/src/app/web/.svelte-kit /usr/src/app/web/coverage /usr/src/app/node_modules /usr/src/app/web/node_modules; do [ -e "$$path" ] && chown -R ${UID:-1000}:${GID:-1000} "$$path" || true; done'
immich-machine-learning:
env_file: !reset []
database:
@@ -42,7 +38,5 @@ services:
redis:
env_file: !reset []
volumes:
# Node modules for each service to avoid conflicts and ensure consistent dependencies
upload1-devcontainer-volume:
upload2-devcontainer-volume:
upload-devcontainer-volume:
postgres-devcontainer-volume:

View File

@@ -32,24 +32,18 @@ jobs:
permissions:
contents: read
outputs:
should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run: ${{ steps.check.outputs.should_run }}
steps:
- name: Checkout code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- id: found_paths
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@24820aa4ef67959b0dcf69a438cccf00d7c7042b # pre-job-action-v1.0.1
with:
filters: |
mobile:
- 'mobile/**'
workflow:
- '.github/workflows/build-mobile.yml'
- name: Check if we should force jobs to run
id: should_force
run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' }}" >> "$GITHUB_OUTPUT"
force-filters: |
- '.github/workflows/build-mobile.yml'
force-events: 'workflow_call,workflow_dispatch'
build-sign-android:
name: Build and sign Android
@@ -57,7 +51,7 @@ jobs:
permissions:
contents: read
# Skip when PR from a fork
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' && needs.pre-job.outputs.should_run == 'true' }}
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' && fromJSON(needs.pre-job.outputs.should_run).mobile == true }}
runs-on: mich
steps:

View File

@@ -35,7 +35,7 @@ jobs:
needs: [get_body, should_run]
if: ${{ needs.should_run.outputs.should_run == 'true' }}
container:
image: yshavit/mdq:0.9.0@sha256:4399483ca857fb1a7ed28a596f754c7373e358647de31ce14b79a27c91e1e35e
image: ghcr.io/immich-app/mdq:main@sha256:d8ae47cf2e6cf4e2559bd57a60b73674fe44f897cba2c2bddff2987a05be10a4
outputs:
checked: ${{ steps.get_checkbox.outputs.checked }}
steps:

View File

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

View File

@@ -20,15 +20,11 @@ jobs:
permissions:
contents: read
outputs:
should_run_server: ${{ steps.found_paths.outputs.server == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run: ${{ steps.check.outputs.should_run }}
steps:
- name: Checkout code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- id: found_paths
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@24820aa4ef67959b0dcf69a438cccf00d7c7042b # pre-job-action-v1.0.1
with:
filters: |
server:
@@ -38,14 +34,11 @@ jobs:
- 'i18n/**'
machine-learning:
- 'machine-learning/**'
workflow:
- '.github/workflows/docker.yml'
- '.github/workflows/multi-runner-build.yml'
- '.github/actions/image-build'
- name: Check if we should force jobs to run
id: should_force
run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'release' }}" >> "$GITHUB_OUTPUT"
force-filters: |
- '.github/workflows/docker.yml'
- '.github/workflows/multi-runner-build.yml'
- '.github/actions/image-build'
force-events: 'workflow_dispatch,release'
retag_ml:
name: Re-Tag ML
@@ -53,7 +46,7 @@ jobs:
permissions:
contents: read
packages: write
if: ${{ needs.pre-job.outputs.should_run_ml == 'false' && !github.event.pull_request.head.repo.fork }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).machine-learning == false && !github.event.pull_request.head.repo.fork }}
runs-on: ubuntu-latest
strategy:
matrix:
@@ -82,7 +75,7 @@ jobs:
permissions:
contents: read
packages: write
if: ${{ needs.pre-job.outputs.should_run_server == 'false' && !github.event.pull_request.head.repo.fork }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).server == false && !github.event.pull_request.head.repo.fork }}
runs-on: ubuntu-latest
strategy:
matrix:
@@ -108,7 +101,7 @@ jobs:
machine-learning:
name: Build and Push ML
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_ml == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).machine-learning == true }}
strategy:
fail-fast: false
matrix:
@@ -153,7 +146,7 @@ jobs:
server:
name: Build and Push Server
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).server == true }}
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@129aeda75a450666ce96e8bc8126652e717917a7 # multi-runner-build-workflow-0.1.1
permissions:
contents: read

View File

@@ -18,32 +18,28 @@ jobs:
permissions:
contents: read
outputs:
should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.found_paths.outputs.open-api == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run: ${{ steps.check.outputs.should_run }}
steps:
- name: Checkout code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- id: found_paths
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@24820aa4ef67959b0dcf69a438cccf00d7c7042b # pre-job-action-v1.0.1
with:
filters: |
docs:
- 'docs/**'
workflow:
- '.github/workflows/docs-build.yml'
open-api:
- 'open-api/immich-openapi-specs.json'
- name: Check if we should force jobs to run
id: should_force
run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'release' || github.ref_name == 'main' }}" >> "$GITHUB_OUTPUT"
force-filters: |
- '.github/workflows/docs-build.yml'
force-events: 'release'
force-branches: 'main'
build:
name: Docs Build
needs: pre-job
permissions:
contents: read
if: ${{ needs.pre-job.outputs.should_run == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).docs == true }}
runs-on: ubuntu-latest
defaults:
run:

View File

@@ -28,6 +28,9 @@ jobs:
token: ${{ steps.generate-token.outputs.token }}
persist-credentials: true
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:

View File

@@ -1,8 +1,15 @@
name: Merge translations
on:
workflow_call:
workflow_dispatch:
workflow_call:
secrets:
PUSH_O_MATIC_APP_ID:
required: true
PUSH_O_MATIC_APP_KEY:
required: true
WEBLATE_TOKEN:
required: true
permissions: {}

View File

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

View File

@@ -0,0 +1,12 @@
name: PR Conventional Commit
on:
pull_request:
types: [opened, synchronize, reopened, edited]
jobs:
validate-pr-title:
name: Validate PR Title (conventional commit)
uses: immich-app/devtools/.github/workflows/shared-pr-require-conventional-commit.yml@main
permissions:
pull-requests: write

15
.github/workflows/org-zizmor.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Zizmor
on:
pull_request:
push:
branches: [main]
jobs:
zizmor:
name: Zizmor
uses: immich-app/devtools/.github/workflows/shared-zizmor.yml@main
permissions:
actions: read
contents: read
security-events: write

View File

@@ -1,19 +0,0 @@
name: PR Conventional Commit Validation
on:
pull_request:
types: [opened, synchronize, reopened, edited]
permissions: {}
jobs:
validate-pr-title:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: PR Conventional Commit Validation
uses: ytanikin/PRConventionalCommits@b628c5a234cc32513014b7bfdd1e47b532124d98 # 1.3.0
with:
task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]'
add_label: 'false'

View File

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

View File

@@ -17,28 +17,23 @@ jobs:
permissions:
contents: read
outputs:
should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run: ${{ steps.check.outputs.should_run }}
steps:
- name: Checkout code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- id: found_paths
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@24820aa4ef67959b0dcf69a438cccf00d7c7042b # pre-job-action-v1.0.1
with:
filters: |
mobile:
- 'mobile/**'
workflow:
- '.github/workflows/static_analysis.yml'
- name: Check if we should force jobs to run
id: should_force
run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'release' }}" >> "$GITHUB_OUTPUT"
force-filters: |
- '.github/workflows/static_analysis.yml'
force-events: 'workflow_dispatch,release'
mobile-dart-analyze:
name: Run Dart Code Analysis
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).mobile == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -100,36 +95,10 @@ jobs:
- name: Run dart format
run: make format
- name: Run dart custom_lint
run: dart run custom_lint
# TODO: Re-enable after upgrading custom_lint
# - name: Run dart custom_lint
# run: dart run custom_lint
# TODO: Use https://github.com/CQLabs/dcm-action
- name: Run DCM
run: dcm analyze lib --fatal-style --fatal-warnings
zizmor:
name: zizmor
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Install the latest version of uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
- name: Run zizmor 🌈
run: uvx zizmor --format=sarif . > results.sarif
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0
with:
sarif_file: results.sarif
category: zizmor

View File

@@ -14,23 +14,11 @@ jobs:
permissions:
contents: read
outputs:
should_run_i18n: ${{ steps.found_paths.outputs.i18n == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_web: ${{ steps.found_paths.outputs.web == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_server: ${{ steps.found_paths.outputs.server == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_cli: ${{ steps.found_paths.outputs.cli == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_e2e: ${{ steps.found_paths.outputs.e2e == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_mobile: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_e2e_web: ${{ steps.found_paths.outputs.e2e == 'true' || steps.found_paths.outputs.web == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_e2e_server_cli: ${{ steps.found_paths.outputs.e2e == 'true' || steps.found_paths.outputs.server == 'true' || steps.found_paths.outputs.cli == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run_.github: ${{ steps.found_paths.outputs['.github'] == 'true' || steps.should_force.outputs.should_force == 'true' }} # redundant to have should_force but if someone changes the trigger then this won't have to be changed
should_run: ${{ steps.check.outputs.should_run }}
steps:
- name: Checkout code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- id: found_paths
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@24820aa4ef67959b0dcf69a438cccf00d7c7042b # pre-job-action-v1.0.1
with:
filters: |
i18n:
@@ -50,17 +38,16 @@ jobs:
- 'mobile/**'
machine-learning:
- 'machine-learning/**'
workflow:
- '.github/workflows/test.yml'
.github:
- '.github/**'
- name: Check if we should force jobs to run
id: should_force
run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'workflow_dispatch' }}" >> "$GITHUB_OUTPUT"
force-filters: |
- '.github/workflows/test.yml'
force-events: 'workflow_dispatch'
server-unit-tests:
name: Test & Lint Server
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).server == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -97,7 +84,7 @@ jobs:
cli-unit-tests:
name: Unit Test CLI
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_cli == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).cli == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -137,7 +124,7 @@ jobs:
cli-unit-tests-win:
name: Unit Test CLI (Windows)
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_cli == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).cli == true }}
runs-on: windows-latest
permissions:
contents: read
@@ -172,7 +159,7 @@ jobs:
web-lint:
name: Lint Web
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_web == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).web == true }}
runs-on: mich
permissions:
contents: read
@@ -209,7 +196,7 @@ jobs:
web-unit-tests:
name: Test Web
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_web == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).web == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -243,7 +230,7 @@ jobs:
i18n-tests:
name: Test i18n
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_i18n == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).i18n == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -281,7 +268,7 @@ jobs:
e2e-tests-lint:
name: End-to-End Lint
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_e2e == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).e2e == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -320,7 +307,7 @@ jobs:
server-medium-tests:
name: Medium Tests (Server)
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).server == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -348,7 +335,7 @@ jobs:
e2e-tests-server-cli:
name: End-to-End Tests (Server & CLI)
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_e2e_server_cli == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).e2e == true || fromJSON(needs.pre-job.outputs.should_run).server == true || fromJSON(needs.pre-job.outputs.should_run).cli == true }}
runs-on: ${{ matrix.runner }}
permissions:
contents: read
@@ -396,7 +383,7 @@ jobs:
e2e-tests-web:
name: End-to-End Tests (Web)
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_e2e_web == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).e2e == true || fromJSON(needs.pre-job.outputs.should_run).web == true }}
runs-on: ${{ matrix.runner }}
permissions:
contents: read
@@ -449,7 +436,7 @@ jobs:
mobile-unit-tests:
name: Unit Test Mobile
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_mobile == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).mobile == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -471,7 +458,7 @@ jobs:
ml-unit-tests:
name: Unit Test ML
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_ml == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).machine-learning == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -507,7 +494,7 @@ jobs:
github-files-formatting:
name: .github Files Formatting
needs: pre-job
if: ${{ needs.pre-job.outputs['should_run_.github'] == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run)['.github'] == true }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -594,7 +581,7 @@ jobs:
contents: read
services:
postgres:
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:4f7ee144d4738ad02f6d9376defed7a767b748d185d47eba241578c26a63064b
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:da52bbead5d818adaa8077c8dcdaad0aaf93038c31ad8348b51f9f0ec1310a4d
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres

View File

@@ -21,25 +21,24 @@ jobs:
permissions:
contents: read
outputs:
should_run: ${{ steps.found_paths.outputs.i18n == 'true' }}
should_run: ${{ steps.check.outputs.should_run }}
steps:
- name: Checkout code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- id: found_paths
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
- name: Check what should run
id: check
uses: immich-app/devtools/actions/pre-job@24820aa4ef67959b0dcf69a438cccf00d7c7042b # pre-job-action-v1.0.1
with:
filters: |
i18n:
- 'i18n/!(en)**\.json'
exclude-branches: 'chore/translations'
skip-force-logic: 'true'
enforce-lock:
name: Check Weblate Lock
needs: [pre-job]
runs-on: ubuntu-latest
permissions: {}
if: ${{ needs.pre-job.outputs.should_run == 'true' }}
if: ${{ fromJSON(needs.pre-job.outputs.should_run).i18n == true }}
steps:
- name: Bot review status
env:

View File

@@ -4,3 +4,4 @@
/web/ @danieldietzler
/machine-learning/ @mertalev
/e2e/ @danieldietzler
/mobile/ @shenlong-tanwen

View File

@@ -1,13 +1,13 @@
dev: prepare-volumes
dev:
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --remove-orphans
dev-down:
docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans
dev-update: prepare-volumes
dev-update:
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
dev-scale: prepare-volumes
dev-scale:
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans
dev-docs:
@@ -23,7 +23,7 @@ e2e-update:
e2e-down:
docker compose -f ./e2e/docker-compose.yml down --remove-orphans
prod:
prod:
@trap 'make prod-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans
prod-down:
@@ -33,16 +33,16 @@ prod-scale:
@trap 'make prod-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.prod.yml up --build -V --scale immich-server=3 --scale immich-microservices=3 --remove-orphans
.PHONY: open-api
open-api: prepare-volumes
open-api:
cd ./open-api && bash ./bin/generate-open-api.sh
open-api-dart: prepare-volumes
open-api-dart:
cd ./open-api && bash ./bin/generate-open-api.sh dart
open-api-typescript: prepare-volumes
open-api-typescript:
cd ./open-api && bash ./bin/generate-open-api.sh typescript
sql: prepare-volumes
sql:
pnpm --filter immich run sync:sql
attach-server:
@@ -68,34 +68,6 @@ VOLUME_DIRS = \
# Include .env file if it exists
-include docker/.env
# Helper function to chown, on error suggest remediation and exit
define safe_chown
if chown $(2) $(or $(UID),1000):$(or $(GID),1000) "$(1)" 2>/dev/null; then \
true; \
else \
STATUS=$$?; echo "Exit code: $$STATUS $(1)"; \
echo "$$STATUS $(1)"; \
echo "Permission denied when changing owner of volumes and upload location. Try running 'sudo make prepare-volumes' first."; \
exit 1; \
fi;
endef
# create empty directories and chown
prepare-volumes:
@$(foreach dir,$(VOLUME_DIRS),mkdir -p $(dir);)
@$(foreach dir,$(VOLUME_DIRS),$(call safe_chown,$(dir),-R))
ifneq ($(UPLOAD_LOCATION),)
ifeq ($(filter /%,$(UPLOAD_LOCATION)),)
@mkdir -p "docker/$(UPLOAD_LOCATION)/photos/upload"
@$(call safe_chown,docker/$(UPLOAD_LOCATION),)
@$(call safe_chown,docker/$(UPLOAD_LOCATION)/photos,-R)
else
@mkdir -p "$(UPLOAD_LOCATION)/photos/upload"
@$(call safe_chown,$(UPLOAD_LOCATION),)
@$(call safe_chown,$(UPLOAD_LOCATION)/photos,-R)
endif
endif
MODULES = e2e server web cli sdk docs .github
# directory to package name mapping function

View File

@@ -1,6 +1,6 @@
{
"name": "@immich/cli",
"version": "2.2.88",
"version": "2.2.90",
"description": "Command Line Interface (CLI) for Immich",
"type": "module",
"exports": "./dist/index.js",
@@ -20,7 +20,7 @@
"@types/lodash-es": "^4.17.12",
"@types/micromatch": "^4.0.9",
"@types/mock-fs": "^4.13.1",
"@types/node": "^22.18.0",
"@types/node": "^22.18.1",
"@vitest/coverage-v8": "^3.0.0",
"byte-size": "^9.0.0",
"cli-progress": "^3.12.0",

View File

@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.52.3"
constraints = "4.52.3"
version = "4.52.5"
constraints = "4.52.5"
hashes = [
"h1:3jU62KY4Oj3xzMwkTQWon1nlIvFkgTCqI93IzUGaa0c=",
"h1:BWimtYXrvbzbbuoVcyobjQnXjjOb9X69JFTw+GuPxfk=",
"h1:C/KvLEm8dVQ6zG2X4asLDtmw2JW/xu7E8MddtaXniO0=",
"h1:Doo0xcLFf+CnfDWjsA7G1NvSLURuwcgyVy8k0NF1gJA=",
"h1:Gc3FGDtR8lUWsi9VImnnE5/USDXiIwYsv4Hbl+d2lwY=",
"h1:HsDY6s1gup5fW9TeuTUy85QMIld1nDOUFlwsfxIq1ig=",
"h1:MnHkB56E4b/kT6WZigsZJnB5rgnCfDVbrLBNxIsEXPY=",
"h1:O/FUQEqhtknJNdsaMbIBi2pLWBds2VvN5FsTVVntzb0=",
"h1:OKQBynkp0J5DIf5FOl/NR3S2rvh89pY+t5wevYxdTJs=",
"h1:On+vPsYV8U/J/8wFZPXjeAgNJqFFQj42vNOKuNKURkY=",
"h1:SPkrMRJahxK0uum7FnUugbGN/JepHMH8M71DBtYrvG0=",
"h1:bEh1ASPMiin3F36+hTfjMQTBnuDl2DzjzSCdova3JEM=",
"h1:dtIK+x5Q1sh5SMPaHBHXhL9XDIqbRW0EBmVZ+KHQB8E=",
"h1:kZcwWfODMWWyauZ66oaO/X+xXkqBtrbYwfUFEtspwEc=",
"zh:53946fce4a631f1d98c61550821c88edede9169dfe5cc254e09a2ab207f76b3f",
"zh:61654a21f1dd4331492d4ef77e9ebff066bc01e1281f92b925e5697c9138d681",
"zh:6a54e9d129b276f052a2f1b73ad0b8735fe6a7403c6a8f6aa111e525eeefaf35",
"zh:7692374e655c346a630b5a7cd776c5e0b2388900dcd7ab69a3af85d0c31c6c43",
"h1:+rfzF+16ZcWZWnTyW/p1HHTzYbPKX8Zt2nIFtR/+f+E=",
"h1:18bXaaOSq8MWKuMxo/4y7EB7/i7G90y5QsKHZRmkoDo=",
"h1:4vZVOpKeEQZsF2VrARRZFeL37Ed/gD4rRMtfnvWQres=",
"h1:BZOsTF83QPKXTAaYqxPKzdl1KRjk/L2qbPpFjM0w28A=",
"h1:CDuC+HXLvc1z6wkCRsSDcc/+QENIHEtssYshiWg3opA=",
"h1:DE+YFzLnqSe79pI2R4idRGx5QzLdrA7RXvngTkGfZ30=",
"h1:DfaJwH3Ml4yrRbdAY4AcDVy0QTQk5T3A622TXzS/u2E=",
"h1:EIDXP0W3kgIv2pecrFmqtK/DnlqkyckzBzhxKaXU+4A=",
"h1:EV4kYyaOnwGA0bh/3hU6Ezqnt1PFDxopH7i85e48IzY=",
"h1:M0iXabfzamU+MPDi0G9XACpbacFKMakmM+Z9HZ8HrsM=",
"h1:YWmCbGF/KbsrUzcYVBLscwLizidbp95TDQa0N2qpmVo=",
"h1:cxPcCB5gbrpUO1+IXkQYs1YTY50/0IlApCzGea0cwuQ=",
"h1:g6DldikTV2HXUu9uoeNY5FuLufgaYWF4ufgZg7wq62s=",
"h1:oi/Hrx9pwoQ+Z52CBC+rrowVH387EIj0qvnxQgDeI+0=",
"zh:1a3400cb38863b2585968d1876706bcfc67a148e1318a1d325c6c7704adc999b",
"zh:4c5062cb9e9da1676f06ae92b8370186d98976cc4c7030d3cd76df12af54282a",
"zh:52110f493b5f0587ef77a1cfd1a67001fd4c617b14c6502d732ab47352bdc2f7",
"zh:5aa536f9eaeb43823aaf2aa80e7d39b25ef2b383405ed034aa16a28b446a9238",
"zh:5cc39459a1c6be8a918f17054e4fbba573825ed5597dcada588fe99614d98a5b",
"zh:629ae6a7ba298815131da826474d199312d21cec53a4d5ded4fa56a692e6f072",
"zh:719cc7c75dc1d3eb30c22ff5102a017996d9788b948078c7e1c5b3446aeca661",
"zh:8698635a3ca04383c1e93b21d6963346bdae54d27177a48e4b1435b7f731731c",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8fe5b792a4d2b1c3a0e573649642962494faa00299baa6aaf813b9a43203dc02",
"zh:a0f403a4862df90f09de65c6e939d6cfd069a8dda2dd33f82948bf6f5f1124ef",
"zh:a25dc3eb60777b600f8f125d321fe7c50b811c5302b58e9a727ceb749a04e35d",
"zh:a2f2ac7dc703c69d2e8c67c9cb5620b5348cb4fd6b98515fbe3f478517b56602",
"zh:d452e7bd24445ee14166470cf50f3aca566d46cab5f26f1c5c988c0f3106b697",
"zh:e10a52b0294735659eb3f0821ad2006ec097918efe58d31d37a5e3c47efef5f6",
"zh:e28dd0954cef9f05adf4d4b440d6f134f605344dfa56307181996675e6550af2",
"zh:f1e3b2f43a472280442f01ba71a3c06c9167432e553381132ea5c4a77e0b6dd5",
"zh:f71fd63718d38fd43829861e91fe79e16d7b4c7c3d508ae3d077368d89b8e5a0",
"zh:faf8d3da4b819c4ae8e565d2b1a684c6a948a086cb299189a5e7b30b2178409d",
"zh:8a9993f1dcadf1dd6ca43b23348abe374605d29945a2fafc07fb3457644e6a54",
"zh:b1b9a1e6bcc24d5863a664a411d2dc906373ae7a2399d2d65548ce7377057852",
"zh:b270184cdeec277218e84b94cb136fead753da717f9b9dc378e51907f3f00bb0",
"zh:dff2bc10071210181726ce270f954995fe42c696e61e2e8f874021fed02521e5",
"zh:e8e87b40b6a87dc097b0fdc20d3f725cec0d82abc9cc3755c1f89f8f6e8b0036",
"zh:ee964a6573d399a5dd22ce328fb38ca1207797a02248f14b2e4913ee390e7803",
]
}

View File

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

View File

@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.52.3"
constraints = "4.52.3"
version = "4.52.5"
constraints = "4.52.5"
hashes = [
"h1:3jU62KY4Oj3xzMwkTQWon1nlIvFkgTCqI93IzUGaa0c=",
"h1:BWimtYXrvbzbbuoVcyobjQnXjjOb9X69JFTw+GuPxfk=",
"h1:C/KvLEm8dVQ6zG2X4asLDtmw2JW/xu7E8MddtaXniO0=",
"h1:Doo0xcLFf+CnfDWjsA7G1NvSLURuwcgyVy8k0NF1gJA=",
"h1:Gc3FGDtR8lUWsi9VImnnE5/USDXiIwYsv4Hbl+d2lwY=",
"h1:HsDY6s1gup5fW9TeuTUy85QMIld1nDOUFlwsfxIq1ig=",
"h1:MnHkB56E4b/kT6WZigsZJnB5rgnCfDVbrLBNxIsEXPY=",
"h1:O/FUQEqhtknJNdsaMbIBi2pLWBds2VvN5FsTVVntzb0=",
"h1:OKQBynkp0J5DIf5FOl/NR3S2rvh89pY+t5wevYxdTJs=",
"h1:On+vPsYV8U/J/8wFZPXjeAgNJqFFQj42vNOKuNKURkY=",
"h1:SPkrMRJahxK0uum7FnUugbGN/JepHMH8M71DBtYrvG0=",
"h1:bEh1ASPMiin3F36+hTfjMQTBnuDl2DzjzSCdova3JEM=",
"h1:dtIK+x5Q1sh5SMPaHBHXhL9XDIqbRW0EBmVZ+KHQB8E=",
"h1:kZcwWfODMWWyauZ66oaO/X+xXkqBtrbYwfUFEtspwEc=",
"zh:53946fce4a631f1d98c61550821c88edede9169dfe5cc254e09a2ab207f76b3f",
"zh:61654a21f1dd4331492d4ef77e9ebff066bc01e1281f92b925e5697c9138d681",
"zh:6a54e9d129b276f052a2f1b73ad0b8735fe6a7403c6a8f6aa111e525eeefaf35",
"zh:7692374e655c346a630b5a7cd776c5e0b2388900dcd7ab69a3af85d0c31c6c43",
"h1:+rfzF+16ZcWZWnTyW/p1HHTzYbPKX8Zt2nIFtR/+f+E=",
"h1:18bXaaOSq8MWKuMxo/4y7EB7/i7G90y5QsKHZRmkoDo=",
"h1:4vZVOpKeEQZsF2VrARRZFeL37Ed/gD4rRMtfnvWQres=",
"h1:BZOsTF83QPKXTAaYqxPKzdl1KRjk/L2qbPpFjM0w28A=",
"h1:CDuC+HXLvc1z6wkCRsSDcc/+QENIHEtssYshiWg3opA=",
"h1:DE+YFzLnqSe79pI2R4idRGx5QzLdrA7RXvngTkGfZ30=",
"h1:DfaJwH3Ml4yrRbdAY4AcDVy0QTQk5T3A622TXzS/u2E=",
"h1:EIDXP0W3kgIv2pecrFmqtK/DnlqkyckzBzhxKaXU+4A=",
"h1:EV4kYyaOnwGA0bh/3hU6Ezqnt1PFDxopH7i85e48IzY=",
"h1:M0iXabfzamU+MPDi0G9XACpbacFKMakmM+Z9HZ8HrsM=",
"h1:YWmCbGF/KbsrUzcYVBLscwLizidbp95TDQa0N2qpmVo=",
"h1:cxPcCB5gbrpUO1+IXkQYs1YTY50/0IlApCzGea0cwuQ=",
"h1:g6DldikTV2HXUu9uoeNY5FuLufgaYWF4ufgZg7wq62s=",
"h1:oi/Hrx9pwoQ+Z52CBC+rrowVH387EIj0qvnxQgDeI+0=",
"zh:1a3400cb38863b2585968d1876706bcfc67a148e1318a1d325c6c7704adc999b",
"zh:4c5062cb9e9da1676f06ae92b8370186d98976cc4c7030d3cd76df12af54282a",
"zh:52110f493b5f0587ef77a1cfd1a67001fd4c617b14c6502d732ab47352bdc2f7",
"zh:5aa536f9eaeb43823aaf2aa80e7d39b25ef2b383405ed034aa16a28b446a9238",
"zh:5cc39459a1c6be8a918f17054e4fbba573825ed5597dcada588fe99614d98a5b",
"zh:629ae6a7ba298815131da826474d199312d21cec53a4d5ded4fa56a692e6f072",
"zh:719cc7c75dc1d3eb30c22ff5102a017996d9788b948078c7e1c5b3446aeca661",
"zh:8698635a3ca04383c1e93b21d6963346bdae54d27177a48e4b1435b7f731731c",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8fe5b792a4d2b1c3a0e573649642962494faa00299baa6aaf813b9a43203dc02",
"zh:a0f403a4862df90f09de65c6e939d6cfd069a8dda2dd33f82948bf6f5f1124ef",
"zh:a25dc3eb60777b600f8f125d321fe7c50b811c5302b58e9a727ceb749a04e35d",
"zh:a2f2ac7dc703c69d2e8c67c9cb5620b5348cb4fd6b98515fbe3f478517b56602",
"zh:d452e7bd24445ee14166470cf50f3aca566d46cab5f26f1c5c988c0f3106b697",
"zh:e10a52b0294735659eb3f0821ad2006ec097918efe58d31d37a5e3c47efef5f6",
"zh:e28dd0954cef9f05adf4d4b440d6f134f605344dfa56307181996675e6550af2",
"zh:f1e3b2f43a472280442f01ba71a3c06c9167432e553381132ea5c4a77e0b6dd5",
"zh:f71fd63718d38fd43829861e91fe79e16d7b4c7c3d508ae3d077368d89b8e5a0",
"zh:faf8d3da4b819c4ae8e565d2b1a684c6a948a086cb299189a5e7b30b2178409d",
"zh:8a9993f1dcadf1dd6ca43b23348abe374605d29945a2fafc07fb3457644e6a54",
"zh:b1b9a1e6bcc24d5863a664a411d2dc906373ae7a2399d2d65548ce7377057852",
"zh:b270184cdeec277218e84b94cb136fead753da717f9b9dc378e51907f3f00bb0",
"zh:dff2bc10071210181726ce270f954995fe42c696e61e2e8f874021fed02521e5",
"zh:e8e87b40b6a87dc097b0fdc20d3f725cec0d82abc9cc3755c1f89f8f6e8b0036",
"zh:ee964a6573d399a5dd22ce328fb38ca1207797a02248f14b2e4913ee390e7803",
]
}

View File

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

View File

@@ -21,16 +21,14 @@ services:
# extends:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
user: '${UID:-1000}:${GID:-1000}'
build:
context: ../
dockerfile: server/Dockerfile
dockerfile: server/Dockerfile.dev
target: dev
restart: unless-stopped
volumes:
- ..:/usr/src/app
- ${UPLOAD_LOCATION}/photos:/data
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
- /etc/localtime:/etc/localtime:ro
- pnpm-store:/usr/src/app/.pnpm-store
- server-node_modules:/usr/src/app/server/node_modules
@@ -72,20 +70,15 @@ services:
condition: service_started
database:
condition: service_started
init:
condition: service_completed_successfully
healthcheck:
disable: false
immich-web:
container_name: immich_web
image: immich-web-dev:latest
# Needed for rootless docker setup, see https://github.com/moby/moby/issues/45919
# user: 0:0
user: '${UID:-1000}:${GID:-1000}'
build:
context: ../
dockerfile: server/Dockerfile
dockerfile: server/Dockerfile.dev
target: dev
command: ['immich-web']
env_file:
@@ -114,8 +107,6 @@ services:
depends_on:
immich-server:
condition: service_started
init:
condition: service_completed_successfully
immich-machine-learning:
container_name: immich_machine_learning
@@ -149,7 +140,7 @@ services:
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:8d292bdb796aa58bbbaa47fe971c8516f6f57d6a47e7172e62754feb6ed4e7b0
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:c44be5f2871c59362966d71eab4268170eb6f5653c0e6170184e72b38ffdf107
env_file:
- .env
environment:
@@ -183,25 +174,6 @@ services:
# volumes:
# - grafana-data:/var/lib/grafana
init:
container_name: init
image: busybox@sha256:ab33eacc8251e3807b85bb6dba570e4698c3998eca6f0fc2ccb60575a563ea74
env_file:
- .env
user: 0:0
command: sh -c 'find /data -maxdepth 1 -type d -exec chown ${UID:-1000}:${GID:-1000} {} + 2>/dev/null || true; for path in /usr/src/app/.pnpm-store /usr/src/app/server/node_modules /usr/src/app/server/dist /usr/src/app/.github/node_modules /usr/src/app/cli/node_modules /usr/src/app/docs/node_modules /usr/src/app/e2e/node_modules /usr/src/app/open-api/typescript-sdk/node_modules /usr/src/app/web/.svelte-kit /usr/src/app/web/coverage /usr/src/app/node_modules /usr/src/app/web/node_modules; do [ -e "$$path" ] && chown -R ${UID:-1000}:${GID:-1000} "$$path" || true; done'
volumes:
- pnpm-store:/usr/src/app/.pnpm-store
- server-node_modules:/usr/src/app/server/node_modules
- web-node_modules:/usr/src/app/web/node_modules
- github-node_modules:/usr/src/app/.github/node_modules
- cli-node_modules:/usr/src/app/cli/node_modules
- docs-node_modules:/usr/src/app/docs/node_modules
- e2e-node_modules:/usr/src/app/e2e/node_modules
- sdk-node_modules:/usr/src/app/open-api/typescript-sdk/node_modules
- app-node_modules:/usr/src/app/node_modules
- sveltekit:/usr/src/app/web/.svelte-kit
- coverage:/usr/src/app/web/coverage
volumes:
model-cache:
prometheus-data:

View File

@@ -63,7 +63,7 @@ services:
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:8d292bdb796aa58bbbaa47fe971c8516f6f57d6a47e7172e62754feb6ed4e7b0
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:c44be5f2871c59362966d71eab4268170eb6f5653c0e6170184e72b38ffdf107
env_file:
- .env
environment:

View File

@@ -56,7 +56,7 @@ services:
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:8d292bdb796aa58bbbaa47fe971c8516f6f57d6a47e7172e62754feb6ed4e7b0
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:c44be5f2871c59362966d71eab4268170eb6f5653c0e6170184e72b38ffdf107
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}

View File

@@ -28,6 +28,12 @@ const guides: CommunityGuidesProps[] = [
description: `synchronize folders in imported library with albums having the folders name.`,
url: 'https://github.com/immich-app/immich/discussions/3382',
},
{
title: 'Immich Podman Quadlets Handbook',
description:
'A rewrite of the original Immich Docker Compose file using Podman Quadlets, with a set of extra guides in the repositorys wiki.',
url: 'https://github.com/linux-universe/immich-podman-quadlets/blob/main/README.md',
},
{
title: 'Podman/Quadlets Install',
description: 'Documentation for simple podman setup using quadlets.',

View File

@@ -110,6 +110,16 @@ const projects: CommunityProjectProps[] = [
description: 'A tiny, zero-login web app for collecting photos/videos from anyone into your Immich server.',
url: 'https://github.com/Nasogaa/immich-drop',
},
{
title: 'Immich Birthday Sync',
description: 'Bulk-upload and -download birthdays, with CardDAV sync support',
url: 'https://github.com/sid3windr/immich-birthday',
},
{
title: 'Immich Stack',
description: 'Auto-stack photos with identical filenames and differing extensions (i.e. JPG+RAW)',
url: 'https://github.com/sid3windr/immich-stack',
},
];
function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {

View File

@@ -2,7 +2,17 @@
## TypeORM Upgrade
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.
If you encountered "Migrations failed: Error: Invalid upgrade path" then perform an intermediate upgrade to `v1.132.3` first.
:::tip
We recommend users upgrade to `v1.132.3` since it does not have any breaking changes or bugs on this upgrade path.
:::
In order to update to Immich `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).
:::caution
Avoid `v1.136.0` if upgrading from `v1.131.0` (or earlier) due to a bug blocking this upgrade in some installations.
:::
## Inconsistent Media Location

View File

@@ -1,4 +1,12 @@
[
{
"label": "v1.142.1",
"url": "https://v1.142.1.archive.immich.app"
},
{
"label": "v1.142.0",
"url": "https://v1.142.0.archive.immich.app"
},
{
"label": "v1.141.1",
"url": "https://v1.141.1.archive.immich.app"

View File

@@ -38,7 +38,7 @@ services:
image: redis:6.2-alpine@sha256:7fe72c486b910f6b1a9769c937dad5d63648ddee82e056f47417542dd40825bb
database:
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:7a4469b9484e37bf2630a60bc2f02f086dae898143b599ecc1c93f619849ef6b
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:11ced39d65a92a54d12890ced6a26cc2003f92697d6f0d4d944b98459dba7138
command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf
environment:
POSTGRES_PASSWORD: postgres

View File

@@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "1.141.1",
"version": "1.142.1",
"description": "",
"main": "index.js",
"type": "module",
@@ -25,7 +25,7 @@
"@playwright/test": "^1.44.1",
"@socket.io/component-emitter": "^3.1.2",
"@types/luxon": "^3.4.2",
"@types/node": "^22.18.0",
"@types/node": "^22.18.1",
"@types/oidc-provider": "^9.0.0",
"@types/pg": "^8.15.1",
"@types/pngjs": "^6.0.4",

View File

@@ -409,6 +409,7 @@
"recent-albums": "Нядаўнія альбомы",
"recent_searches": "Нядаўнія пошукі",
"recently_added": "Нядаўна дададзена",
"refresh_faces": "Абнавіць твары",
"remove": "Выдаліць",
"remove_from_album": "Выдаліць з альбома",
"remove_from_favorites": "Выдаліць з абраных",

View File

@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "Mobile-App ist veraltet. Bitte aktualisiere auf die neueste Minor-Version.",
"profile_drawer_client_server_up_to_date": "Die App- und Server-Versionen sind aktuell",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Schreibgeschützter Modus aktiviert. Tippe zweimal auf das Benutzer-Avatar-Symbol, um den Modus zu verlassen.",
"profile_drawer_readonly_mode": "Schreibgeschützter Modus aktiviert. Halte das Benutzer-Avatar-Symbol gedrückt, um den Modus zu verlassen.",
"profile_drawer_server_out_of_date_major": "Server-Version ist veraltet. Bitte aktualisiere auf die neueste Major-Version.",
"profile_drawer_server_out_of_date_minor": "Server-Version ist veraltet. Bitte aktualisiere auf die neueste Minor-Version.",
"profile_image_of_user": "Profilbild von {user}",
@@ -1547,7 +1547,7 @@
"purchase_per_server": "Pro Server",
"purchase_per_user": "Pro Benutzer",
"purchase_remove_product_key": "Produktschlüssel entfernen",
"purchase_remove_product_key_prompt": "Sicher, dass der Produktschlüssel entfernt werden soll?",
"purchase_remove_product_key_prompt": "Bist Du sicher, dass der Produktschlüssel entfernt werden soll?",
"purchase_remove_server_product_key": "Server-Produktschlüssel entfernen",
"purchase_remove_server_product_key_prompt": "Sicher, dass der Server-Produktschlüssel entfernt werden soll?",
"purchase_server_description_1": "Für den gesamten Server",
@@ -1917,6 +1917,8 @@
"sync_albums_manual_subtitle": "Synchronisiere alle hochgeladenen Videos und Fotos in die ausgewählten Backup-Alben",
"sync_local": "Lokal synchronisieren",
"sync_remote": "mit Server synchronisieren",
"sync_status": "Synchronisierungstatus",
"sync_status_subtitle": "Synchronisierungssystem anzeigen und bearbeiten",
"sync_upload_album_setting_subtitle": "Erstelle deine ausgewählten Alben in Immich und lade die Fotos und Videos dort hoch",
"tag": "Tag",
"tag_assets": "Dateien taggen",
@@ -1976,6 +1978,7 @@
"trash_page_select_assets_btn": "Elemente auswählen",
"trash_page_title": "Papierkorb ({count})",
"trashed_items_will_be_permanently_deleted_after": "Gelöschte Objekte werden nach {days, plural, one {# Tag} other {# Tagen}} endgültig gelöscht.",
"troubleshoot": "Fehler beheben",
"type": "Typ",
"unable_to_change_pin_code": "PIN Code konnte nicht geändert werden",
"unable_to_setup_pin_code": "PIN Code konnte nicht festgelegt werden",

View File

@@ -387,8 +387,6 @@
"admin_password": "Admin Password",
"administration": "Administration",
"advanced": "Advanced",
"advanced_settings_beta_timeline_subtitle": "Try the new app experience",
"advanced_settings_beta_timeline_title": "Beta Timeline",
"advanced_settings_enable_alternate_media_filter_subtitle": "Use this option to filter media during sync based on alternate criteria. Only try this if you have issues with the app detecting all albums.",
"advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTAL] Use alternate device album sync filter",
"advanced_settings_log_level_title": "Log level: {level}",
@@ -425,6 +423,7 @@
"album_remove_user_confirmation": "Are you sure you want to remove {user}?",
"album_search_not_found": "No albums found matching your search",
"album_share_no_users": "Looks like you have shared this album with all users or you don't have any user to share with.",
"album_summary": "Album summary",
"album_updated": "Album updated",
"album_updated_setting_description": "Receive an email notification when a shared album has new assets",
"album_user_left": "Left {album}",
@@ -496,6 +495,8 @@
"asset_restored_successfully": "Asset restored successfully",
"asset_skipped": "Skipped",
"asset_skipped_in_trash": "In trash",
"asset_trashed": "Asset trashed",
"asset_troubleshoot": "Asset Troubleshoot",
"asset_uploaded": "Uploaded",
"asset_uploading": "Uploading…",
"asset_viewer_settings_subtitle": "Manage your gallery viewer settings",
@@ -529,8 +530,10 @@
"autoplay_slideshow": "Autoplay slideshow",
"back": "Back",
"back_close_deselect": "Back, close, or deselect",
"background_backup_running_error": "Background backup is currently running, cannot start manual backup",
"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_options": "Background Options",
"backup": "Backup",
"backup_album_selection_page_albums_device": "Albums on device ({count})",
"backup_album_selection_page_albums_tap": "Tap to include, double tap to exclude",
@@ -538,6 +541,7 @@
"backup_album_selection_page_select_albums": "Select albums",
"backup_album_selection_page_selection_info": "Selection Info",
"backup_album_selection_page_total_assets": "Total unique assets",
"backup_albums_sync": "Backup albums synchronization",
"backup_all": "All",
"backup_background_service_backup_failed_message": "Failed to backup assets. Retrying…",
"backup_background_service_connection_failed_message": "Failed to connect to the server. Retrying…",
@@ -654,6 +658,8 @@
"change_pin_code": "Change PIN code",
"change_your_password": "Change your password",
"changed_visibility_successfully": "Changed visibility successfully",
"charging": "Charging",
"charging_requirement_mobile_backup": "Background backup requires the device to be charging",
"check_corrupt_asset_backup": "Check for corrupt asset backups",
"check_corrupt_asset_backup_button": "Perform check",
"check_corrupt_asset_backup_description": "Run this check only over Wi-Fi and once all assets have been backed-up. The procedure might take a few minutes.",
@@ -740,6 +746,7 @@
"create_user": "Create user",
"created": "Created",
"created_at": "Created",
"creating_linked_albums": "Creating linked albums...",
"crop": "Crop",
"curated_object_page_title": "Things",
"current_device": "Current device",
@@ -889,7 +896,9 @@
"error": "Error",
"error_change_sort_album": "Failed to change album sort order",
"error_delete_face": "Error deleting face from asset",
"error_getting_places": "Error getting places",
"error_loading_image": "Error loading image",
"error_loading_partners": "Error loading partners: {error}",
"error_saving_image": "Error: {error}",
"error_tag_face_bounding_box": "Error tagging face - cannot get bounding box coordinates",
"error_title": "Error - Something went wrong",
@@ -1054,6 +1063,7 @@
"favorites_page_no_favorites": "No favorite assets found",
"feature_photo_updated": "Feature photo updated",
"features": "Features",
"features_in_development": "Features in Development",
"features_setting_description": "Manage the app features",
"file_name": "File name",
"file_name_or_extension": "File name or extension",
@@ -1218,6 +1228,7 @@
"local": "Local",
"local_asset_cast_failed": "Unable to cast an asset that is not uploaded to the server",
"local_assets": "Local Assets",
"local_media_summary": "Local Media Summary",
"local_network": "Local network",
"local_network_sheet_info": "The app will connect to the server through this URL when using the specified Wi-Fi network",
"location_permission": "Location permission",
@@ -1229,6 +1240,7 @@
"location_picker_longitude_hint": "Enter your longitude here",
"lock": "Lock",
"locked_folder": "Locked Folder",
"log_detail_title": "Log Detail",
"log_out": "Log out",
"log_out_all_devices": "Log Out All Devices",
"logged_in_as": "Logged in as {user}",
@@ -1259,6 +1271,7 @@
"login_password_changed_success": "Password updated successfully",
"logout_all_device_confirmation": "Are you sure you want to log out all devices?",
"logout_this_device_confirmation": "Are you sure you want to log out this device?",
"logs": "Logs",
"longitude": "Longitude",
"look": "Look",
"loop_videos": "Loop videos",
@@ -1301,6 +1314,7 @@
"mark_as_read": "Mark as read",
"marked_all_as_read": "Marked all as read",
"matches": "Matches",
"matching_assets": "Matching Assets",
"media_type": "Media type",
"memories": "Memories",
"memories_all_caught_up": "All caught up",
@@ -1339,8 +1353,11 @@
"my_albums": "My albums",
"name": "Name",
"name_or_nickname": "Name or nickname",
"navigate": "Navigate",
"navigate_to_time": "Navigate to Time",
"network_requirement_photos_upload": "Use cellular data to backup photos",
"network_requirement_videos_upload": "Use cellular data to backup videos",
"network_requirements": "Network Requirements",
"network_requirements_updated": "Network requirements changed, resetting backup queue",
"networking_settings": "Networking",
"networking_subtitle": "Manage the server endpoint settings",
@@ -1351,6 +1368,7 @@
"new_person": "New person",
"new_pin_code": "New PIN code",
"new_pin_code_subtitle": "This is your first time accessing the locked folder. Create a PIN code to securely access this page",
"new_timeline": "New Timeline",
"new_user_created": "New user created",
"new_version_available": "NEW VERSION AVAILABLE",
"newest_first": "Newest first",
@@ -1364,20 +1382,25 @@
"no_assets_message": "CLICK TO UPLOAD YOUR FIRST PHOTO",
"no_assets_to_show": "No assets to show",
"no_cast_devices_found": "No cast devices found",
"no_checksum_local": "No checksum available - cannot fetch local assets",
"no_checksum_remote": "No checksum available - cannot fetch remote asset",
"no_duplicates_found": "No duplicates were found.",
"no_exif_info_available": "No exif info available",
"no_explore_results_message": "Upload more photos to explore your collection.",
"no_favorites_message": "Add favorites to quickly find your best pictures and videos",
"no_libraries_message": "Create an external library to view your photos and videos",
"no_local_assets_found": "No local assets found with this checksum",
"no_locked_photos_message": "Photos and videos in the locked folder are hidden and won't show up as you browse or search your library.",
"no_name": "No Name",
"no_notifications": "No notifications",
"no_people_found": "No matching people found",
"no_places": "No places",
"no_remote_assets_found": "No remote assets found with this checksum",
"no_results": "No results",
"no_results_description": "Try a synonym or more general keyword",
"no_shared_albums_message": "Create an album to share photos and videos with people in your network",
"no_uploads_in_progress": "No uploads in progress",
"not_available": "N/A",
"not_in_any_album": "Not in any album",
"not_selected": "Not selected",
"note_apply_storage_label_to_previously_uploaded assets": "Note: To apply the Storage Label to previously uploaded assets, run the",
@@ -1588,6 +1611,7 @@
"regenerating_thumbnails": "Regenerating thumbnails",
"remote": "Remote",
"remote_assets": "Remote Assets",
"remote_media_summary": "Remote Media Summary",
"remove": "Remove",
"remove_assets_album_confirmation": "Are you sure you want to remove {count, plural, one {# asset} other {# assets}} from the album?",
"remove_assets_shared_link_confirmation": "Are you sure you want to remove {count, plural, one {# asset} other {# assets}} from this shared link?",
@@ -1863,6 +1887,7 @@
"show_slideshow_transition": "Show slideshow transition",
"show_supporter_badge": "Supporter badge",
"show_supporter_badge_description": "Show a supporter badge",
"show_text_search_menu": "Show text search menu",
"shuffle": "Shuffle",
"sidebar": "Sidebar",
"sidebar_display_description": "Display a link to the view in the sidebar",
@@ -2095,5 +2120,6 @@
"yes": "Yes",
"you_dont_have_any_shared_links": "You don't have any shared links",
"your_wifi_name": "Your Wi-Fi name",
"zoom_image": "Zoom Image"
"zoom_image": "Zoom Image",
"zoom_to_bounds": "Zoom to bounds"
}

View File

@@ -38,7 +38,7 @@
"added_to_favorites_count": "Agregado {count, number} a favoritos",
"admin": {
"add_exclusion_pattern_description": "Agrega patrones de exclusión. Puedes utilizar los caracteres *, ** y ? (globbing). Ejemplos: para ignorar todos los archivos en cualquier directorio llamado \"Raw\", utiliza \"**/Raw/**\". Para ignorar todos los archivos que terminan en \".tif\", utiliza \"**/*.tif\". Para ignorar una ruta absoluta, utiliza \"/carpeta/a/ignorar/**\".",
"admin_user": "Usuario administrativo",
"admin_user": "Usuario administrador",
"asset_offline_description": "Este recurso externo de la biblioteca ya no se encuentra en el disco y se ha movido a la papelera. Si el archivo se movió dentro de la biblioteca, comprueba la línea temporal para el nuevo recurso correspondiente. Para restaurar este recurso, asegúrate de que Immich puede acceder a la siguiente ruta de archivo y escanear la biblioteca.",
"authentication_settings": "Parámetros de autenticación",
"authentication_settings_description": "Gestionar contraseñas, OAuth y otros parámetros de autenticación",
@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "La app está desactualizada. Por favor actualiza a la última versión menor.",
"profile_drawer_client_server_up_to_date": "Cliente y Servidor están actualizados",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Modo Solo lectura habilitado. Toque dos veces el ícono del avatar del usuario para salir.",
"profile_drawer_readonly_mode": "Modo Solo lectura habilitado. Mantén pulsado el icono del avatar del usuario para salir.",
"profile_drawer_server_out_of_date_major": "El servidor está desactualizado. Por favor actualiza a la última versión principal.",
"profile_drawer_server_out_of_date_minor": "El servidor está desactualizado. Por favor actualiza a la última versión menor.",
"profile_image_of_user": "Foto de perfil de {user}",
@@ -1917,6 +1917,8 @@
"sync_albums_manual_subtitle": "Sincroniza todos los videos y fotos subidos con los álbumes seleccionados a respaldar",
"sync_local": "Sincronización Local",
"sync_remote": "Sincronización Remota",
"sync_status": "Estado de la sincronización",
"sync_status_subtitle": "Ver y gestionar el estado de la sincronización",
"sync_upload_album_setting_subtitle": "Crea y sube tus fotos y videos a los álbumes seleccionados en Immich",
"tag": "Etiqueta",
"tag_assets": "Etiquetar activos",
@@ -1976,6 +1978,7 @@
"trash_page_select_assets_btn": "Seleccionar elementos",
"trash_page_title": "Papelera ({count})",
"trashed_items_will_be_permanently_deleted_after": "Los elementos en la papelera serán eliminados permanentemente tras {days, plural, one {# día} other {# días}}.",
"troubleshoot": "Solucionar problemas",
"type": "Tipo",
"unable_to_change_pin_code": "No se ha podido cambiar el PIN",
"unable_to_setup_pin_code": "No se ha podido establecer el PIN",

View File

@@ -42,6 +42,7 @@
"authentication_settings_description": "Kudeatu pasahitza, OAuth edo beste segurtasun konfigurazio bat",
"authentication_settings_disable_all": "Seguru zaude saioa hasteko modu guztiak desgaitu nahi dituzula? Saioa hastea guztiz desgaitua izango da.",
"authentication_settings_reenable": "Berriro gaitzeko, erabili <link>Server Command</link>.",
"background_task_job": "Atzealdeko Lanak",
"backup_onboarding_footer": "Immich-en babes kopiei buruzko informazio gehiago nahi baduzu, mesedez irakurri <link>dokumentazioa</link>.",
"backup_onboarding_title": "Babes Kopiak",
"confirm_delete_library": "Seguru zaude {library} ezabatu nahi duzula?",
@@ -62,6 +63,15 @@
"job_created": "Zeregina sortuta",
"job_settings": "Zereginaren konfigurazioa",
"job_status": "Zereginaren Egoera",
"logging_enable_description": "Gaitu erregistroak",
"logging_level_description": "Erregistroak gaituta daudenean, nolako erregistro maila erabili.",
"logging_settings": "Erregistroak",
"machine_learning_duplicate_detection": "Bizkoizketa Detekzioa",
"machine_learning_duplicate_detection_enabled": "Gaitu bikoizketa detekezioa",
"machine_learning_facial_recognition": "Aurpegi-Ezagutza",
"machine_learning_facial_recognition_description": "Detektatu, ezagutu eta aurpegiak banatu argazkietan",
"machine_learning_facial_recognition_model": "Aurpegi-Ezagutza eredua",
"machine_learning_facial_recognition_setting": "Aurpegi-Ezagutza Gaitu",
"machine_learning_smart_search_enabled": "Gaitu bilaketa arina",
"manage_log_settings": "Kudeatu erregistroen konfigurazioa",
"map_dark_style": "Beltz estiloa",

View File

@@ -389,7 +389,7 @@
"advanced": "Avancé",
"advanced_settings_beta_timeline_subtitle": "Essayer la nouvelle application",
"advanced_settings_beta_timeline_title": "Timeline de la béta",
"advanced_settings_enable_alternate_media_filter_subtitle": "Utilisez cette option pour filtrer les média durant la synchronisation avec des critères alternatifs. N'utilisez cela que lorsque l'application n'arrive pas à détecter tout les albums.",
"advanced_settings_enable_alternate_media_filter_subtitle": "Utilisez cette option pour filtrer les média durant la synchronisation avec des critères alternatifs. N'utilisez cela que lorsque l'application n'arrive pas à détecter tous les albums.",
"advanced_settings_enable_alternate_media_filter_title": "[EXPÉRIMENTAL] Utiliser le filtre de synchronisation d'album alternatif",
"advanced_settings_log_level_title": "Niveau de journalisation : {level}",
"advanced_settings_prefer_remote_subtitle": "Certains appareils sont très lents à charger des miniatures à partir de ressources locales. Activez ce paramètre pour charger des images externes à la place.",
@@ -1964,7 +1964,7 @@
"total": "Total",
"total_usage": "Utilisation globale",
"trash": "Corbeille",
"trash_action_prompt": "{count} mis à la corbeille",
"trash_action_prompt": "{count} média(s) mis à la corbeille",
"trash_all": "Tout supprimer",
"trash_count": "Corbeille {count, number}",
"trash_delete_asset": "Mettre à la corbeille/Supprimer un média",

View File

@@ -14,6 +14,7 @@
"add_a_location": "Engadir unha ubicación",
"add_a_name": "Engadir un nome",
"add_a_title": "Engadir un título",
"add_birthday": "Engadir cumpleanos",
"add_endpoint": "Engadir endpoint",
"add_exclusion_pattern": "Engadir patrón de exclusión",
"add_import_path": "Engadir ruta de importación",
@@ -22,10 +23,14 @@
"add_partner": "Engadir compañeiro/a",
"add_path": "Engadir ruta",
"add_photos": "Engadir fotos",
"add_tag": "Engadir etiqueta",
"add_to": "Engadir a…",
"add_to_album": "Engadir ao álbum",
"add_to_album_bottom_sheet_added": "Engadido a {album}",
"add_to_album_bottom_sheet_already_exists": "Xa está en {album}",
"add_to_album_toggle": "Alternar selección para o {album}",
"add_to_albums": "Engadir en álbums",
"add_to_albums_count": "Engadir a {count} álbums",
"add_to_shared_album": "Engadir ao álbum compartido",
"add_url": "Engadir URL",
"added_to_archive": "Engadido ao arquivo",
@@ -33,6 +38,7 @@
"added_to_favorites_count": "Engadido {count, number} a favoritos",
"admin": {
"add_exclusion_pattern_description": "Engadir patróns de exclusión. Admítense caracteres comodín usando *, ** e ?. Para ignorar todos os ficheiros en calquera directorio chamado \"Raw\", emprega \"**/Raw/**\". Para ignorar todos os ficheiros que rematen en \".tif\", usa \"**/*.tif\". Para ignorar unha ruta absoluta, emprega \"/ruta/a/ignorar/**\".",
"admin_user": "Usuario administrador",
"asset_offline_description": "Este activo da biblioteca externa xa non se atopa no disco e moveuse ao lixo. Se o ficheiro se moveu dentro da biblioteca, comproba a túa liña de tempo para o novo activo correspondente. Para restaurar este activo, asegúrate de que Immich poida acceder á ruta do ficheiro a continuación e escanee a biblioteca.",
"authentication_settings": "Configuración de autenticación",
"authentication_settings_description": "Xestionar contrasinal, OAuth e outras configuracións de autenticación",

View File

@@ -1093,7 +1093,7 @@
"haptic_feedback_switch": "אפשר משוב ברטט",
"haptic_feedback_title": "משוב ברטט",
"has_quota": "יש מכסה",
"hash_asset": יבוב תמונה",
"hash_asset": בב פריט",
"hashed_assets": "תמונות מגובבות",
"hashing": "מגבב",
"header_settings_add_header_tip": "הוסף כותרת",
@@ -1129,7 +1129,7 @@
"hour": "שעה",
"hours": "שעות",
"id": "מזהה",
"idle": "ממתין",
"idle": "במצב סרק",
"ignore_icloud_photos": "התעלם מתמונות iCloud",
"ignore_icloud_photos_description": "תמונות שמאוחסנות ב-iCloud לא יועלו לשרת",
"image": "תמונה",
@@ -1412,6 +1412,8 @@
"open_the_search_filters": "פתח את מסנני החיפוש",
"options": "אפשרויות",
"or": "או",
"organize_into_albums": "ארגן בתוך אלבומים",
"organize_into_albums_description": "שים תמונות קיימות בתוך אלבומים באמצעות הגדרות הסנכרון הנוכחיות",
"organize_your_library": "ארגן את הספרייה שלך",
"original": "מקורי",
"other": "אחר",
@@ -1471,9 +1473,9 @@
"permission_onboarding_permission_limited": "הרשאה מוגבלת. כדי לתת ליישום לגבות ולנהל את כל אוסף הגלריה שלך, הענק הרשאה לתמונות וסרטונים בהגדרות.",
"permission_onboarding_request": "היישום דורש הרשאה כדי לראות את התמונות והסרטונים שלך.",
"person": "אדם",
"person_age_months": ן {months, plural, one {חודש #} other {# חודשים}}",
"person_age_year_months": ן שנה, {months, plural, one {חודש #} other {# חודשים}}",
"person_age_years": ן {years, plural, other {# שנים}}",
"person_age_months": גיל {months, plural, one {חודש #} other {# חודשים}}",
"person_age_year_months": גיל שנה ו{months, plural, one {חודש #} other {# חודשים}}",
"person_age_years": גיל {years, plural, other {# שנים}}",
"person_birthdate": "נולד בתאריך {date}",
"person_hidden": "{name}{hidden, select, true { (מוסתר)} other {}}",
"photo_shared_all_users": "נראה ששיתפת את התמונות שלך עם כל המשתמשים או שאין לך אף משתמש לשתף איתו.",
@@ -1513,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "גרסת היישום לנייד מיושנת. נא לעדכן לגרסה המשנית האחרונה.",
"profile_drawer_client_server_up_to_date": "היישום והשרת מעודכנים",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "מצב לקריאה בלבד מופעל. הקש הקשה כפולה על סמל היצגן של המשתמש כדי לצאת.",
"profile_drawer_readonly_mode": "מצב לקריאה בלבד מופעל. לחץ לחיצה ארוכה על סמל היצגן של המשתמש כדי לצאת.",
"profile_drawer_server_out_of_date_major": "השרת אינו מעודכן. נא לעדכן לגרסה הראשית האחרונה.",
"profile_drawer_server_out_of_date_minor": "השרת אינו מעודכן. נא לעדכן לגרסה המשנית האחרונה.",
"profile_image_of_user": "תמונת פרופיל של {user}",
@@ -1552,7 +1554,8 @@
"purchase_server_description_2": "מעמד תומך",
"purchase_server_title": "שרת",
"purchase_settings_server_activated": "מפתח המוצר של השרת מנוהל על ידי מנהל המערכת",
"queue_status": "בתור {count}/{total}",
"query_asset_id": "שאילתה על מזהה הפריט",
"queue_status": "{count} מתוך {total} עומדים בתור",
"rating": "דירוג כוכב",
"rating_clear": "נקה דירוג",
"rating_count": "{count, plural, one {כוכב #} other {# כוכבים}}",
@@ -1637,6 +1640,7 @@
"restore_user": "שחזר משתמש",
"restored_asset": "התמונה שוחזרה",
"resume": "המשך",
"resume_paused_jobs": "המשך {count, plural, one {עבודה # שהופסקה} other {# עבודות שהופסקו}}",
"retry_upload": "נסה שוב להעלות",
"review_duplicates": "בדוק כפילויות",
"review_large_files": "צפייה בקבצים גדולים",
@@ -1903,7 +1907,7 @@
"submit": "שלח",
"success": "בוצע בהצלחה",
"suggestions": "הצעות",
"sunrise_on_the_beach": "Sunrise on the beach (מומלץ לחפש באנגלית לתוצאות טובות יותר)",
"sunrise_on_the_beach": "שקיעה בחוף",
"support": "תמיכה",
"support_and_feedback": "תמיכה & משוב",
"support_third_party_description": "התקנת ה-Immich שלך נארזה על ידי צד שלישי. בעיות שאתה חווה עשויות להיגרם על ידי חבילה זו, אז בבקשה תעלה בעיות איתם ראשית כל באמצעות הקישורים למטה.",
@@ -1912,7 +1916,9 @@
"sync_albums": "סנכרן אלבומים",
"sync_albums_manual_subtitle": "סנכרן את כל הסרטונים והתמונות שהועלו לאלבומי הגיבוי שנבחרו",
"sync_local": "סנכרן מקומי",
"sync_remote": "סנכרן מרוחק",
"sync_remote": "סנכרן נקודת קצה מרוחקת",
"sync_status": "סנכרן מצב",
"sync_status_subtitle": "הצג ונהל את מערכת הסנכרון",
"sync_upload_album_setting_subtitle": "צור והעלה תמונות וסרטונים שלך לאלבומים שנבחרו ביישום",
"tag": "תג",
"tag_assets": "תיוג תמונות",
@@ -1972,6 +1978,7 @@
"trash_page_select_assets_btn": "בחר תמונות",
"trash_page_title": "אשפה ({count})",
"trashed_items_will_be_permanently_deleted_after": "פריטים באשפה ימחקו לצמיתות לאחר {days, plural, one {יום #} other {# ימים}}.",
"troubleshoot": "פתור בעיות",
"type": "סוג",
"unable_to_change_pin_code": "לא ניתן לשנות את קוד ה PIN",
"unable_to_setup_pin_code": "לא ניתן להגדיר קוד PIN",
@@ -2069,6 +2076,7 @@
"view_next_asset": "הצג את התמונה הבאה",
"view_previous_asset": "הצג את התמונה הקודמת",
"view_qr_code": "הצג ברקוד",
"view_similar_photos": "הצג תמונות דומות",
"view_stack": "הצג ערימה",
"view_user": "הצג משתמש",
"viewer_remove_from_stack": "הסר מערימה",

View File

@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "L'applicazione non è aggiornata. Aggiorna all'ultima versione minore.",
"profile_drawer_client_server_up_to_date": "Client e server sono aggiornati",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Modalità di sola lettura abilitata. Tocca due volte l'icona dell'avatar dell'utente per disabilitarla.",
"profile_drawer_readonly_mode": "Modalità di sola lettura abilitata. Tieni premuto sull'avatar dell'utente per disabilitarla.",
"profile_drawer_server_out_of_date_major": "Il server non è aggiornato. Aggiorna all'ultima versione principale.",
"profile_drawer_server_out_of_date_minor": "Il server non è aggiornato. Aggiorna all'ultima versione minore.",
"profile_image_of_user": "Immagine profilo di {user}",

View File

@@ -1473,9 +1473,9 @@
"permission_onboarding_permission_limited": "写真へのアクセスが制限されています。Immichが写真のバックアップと管理を行うには、システム設定から写真と動画のアクセス権限を変更してください。",
"permission_onboarding_request": "Immichは写真へのアクセス許可が必要です",
"person": "人物",
"person_age_months": "{months, plural, one {# ヶ月} other {# ヶ月}}",
"person_age_year_months": "1 , {months, plural, one {# ヶ月} other {# ヶ月}}",
"person_age_years": "{years, plural, other {# }}",
"person_age_months": "生後 {months, plural, one {# ヶ月} other {# ヶ月}}",
"person_age_year_months": "1 歳と, {months, plural, one {# ヶ月} other {# ヶ月}}",
"person_age_years": "{years, plural, other {# }}",
"person_birthdate": "{date}生まれ",
"person_hidden": "{name}{hidden, select, true { (非表示)} other {}}",
"photo_shared_all_users": "写真をすべてのユーザーと共有したか、共有するユーザーがいないようです。",
@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "アプリが更新されてません。最新のバージョンに更新してください",
"profile_drawer_client_server_up_to_date": "すべて最新版です",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "読み取り専用モードが有効です。ユーザーのアイコンをダブルタップして読み取り専用モードを解除してください。",
"profile_drawer_readonly_mode": "読み取り専用モードが有効です。ユーザーのアイコンを長押しして読み取り専用モードを解除してください。",
"profile_drawer_server_out_of_date_major": "サーバーが更新されてません。最新のバージョンに更新してください",
"profile_drawer_server_out_of_date_minor": "サーバーが更新されてません。最新のバージョンに更新してください",
"profile_image_of_user": "{user} のプロフィール画像",
@@ -1640,6 +1640,7 @@
"restore_user": "ユーザーを復元",
"restored_asset": "項目を復元しました",
"resume": "再開",
"resume_paused_jobs": "再開: {count, plural, one {# paused job} other {# paused jobs}}",
"retry_upload": "アップロードを再試行",
"review_duplicates": "重複を調査",
"review_large_files": "サイズの大きなファイルを見る",
@@ -1916,6 +1917,8 @@
"sync_albums_manual_subtitle": "アップロード済みの全ての写真や動画を選択されたバックアップアルバムに同期する",
"sync_local": "ローカルを同期",
"sync_remote": "リモートを同期",
"sync_status": "同期の状態",
"sync_status_subtitle": "同期システムを確認・管理",
"sync_upload_album_setting_subtitle": "サーバー上のアルバムの内容を端末上のアルバムと同期します (サーバーにアルバムが無い場合自動で作成されます。また、アップロードされていない写真や動画は同期されません)",
"tag": "タグ付けする",
"tag_assets": "アセットにタグ付けする",
@@ -1975,6 +1978,7 @@
"trash_page_select_assets_btn": "項目を選択",
"trash_page_title": "ゴミ箱 ({count})",
"trashed_items_will_be_permanently_deleted_after": "ゴミ箱に入れられたアイテムは{days, plural, one {#日} other {#日}}後に完全に削除されます。",
"troubleshoot": "トラブルシューティング",
"type": "タイプ",
"unable_to_change_pin_code": "PINコードを変更できませんでした",
"unable_to_setup_pin_code": "PINコードをセットアップできませんでした",
@@ -2024,7 +2028,7 @@
"upload_success": "アップロード成功、新しくアップロードされたアセットを見るにはページを更新してください。",
"upload_to_immich": "Immichにアップロード ({count})",
"uploading": "アップロード中",
"uploading_media": "メディアをアップロード",
"uploading_media": "メディアをアップロード",
"url": "URL",
"usage": "使用容量",
"use_biometric": "生体認証をご利用ください",

View File

@@ -28,13 +28,16 @@
"add_to_album": "Pridėti į albumą",
"add_to_album_bottom_sheet_added": "Pridėta į {album}",
"add_to_album_bottom_sheet_already_exists": "Jau yra albume {album}",
"add_to_album_toggle": "Perjungti pažymėjimus albumui {album}",
"add_to_albums": "Pridėti į albumus",
"add_to_albums_count": "Pridėti į albumus ({count})",
"add_to_shared_album": "Pridėti į bendrinamą albumą",
"add_url": "Pridėti URL",
"added_to_archive": "Pridėta į archyvą",
"added_to_favorites": "Pridėta prie mėgstamiausių",
"added_to_favorites_count": "{count, plural, one {# pridėtas} few {# pridėti} other {# pridėta}} prie mėgstamiausių",
"admin": {
"add_exclusion_pattern_description": "Pridėti išimčių taisyklęs. Plaikomi simboliai *,**, ir ?. Ignoruoti bet kokius failus bet kuriame aplanke vadintame \"Raw\", naudokite \"**/RAW/**\". Ignoravimui failų su plėtiniu \".tif\", naudokite \"**/*.tiff\". Aplanko kelio nustatymams, naudokite \"/aplanko/kelias/ignoruoti/**\"",
"add_exclusion_pattern_description": "Pridėti išimčių taisykles. Palaikomi simboliai *,**, ir ?. Ignoruoti bet kokius failus bet kuriame aplanke pavadintame \"Raw\", naudokite \"**/RAW/**\". Ignoravimui failų su plėtiniu \".tif\", naudokite \"**/*.tiff\". Aplanko kelio nustatymams, naudokite \"/aplanko/kelias/ignoruoti/**\".",
"admin_user": "Administratorius",
"asset_offline_description": "Šis išorinės bibliotekos elementas nebepasiekiamas diske ir buvo perkeltas į šiukšliadėžę. Jei failas buvo perkeltas toje pačioje bibliotekoje, laiko skalėje rasite naują atitinkamą elementą. Jei norite šį elementą atkurti, įsitikinkite, kad Immich gali pasiekti failą žemiau nurodytu adresu, ir suvykdykite bibliotekos skenavimą.",
"authentication_settings": "Autentifikavimo nustatymai",
@@ -45,6 +48,10 @@
"backup_database": "Sukurti duomenų bazės išklotinę",
"backup_database_enable_description": "Įgalinti duomenų bazės išklotinės",
"backup_keep_last_amount": "Išsaugomų ankstesnių duomenų bazės išklotinių skaičius",
"backup_onboarding_1_description": "išorinė kopija debesyje arba kitoje fizinėje lokacijoje.",
"backup_onboarding_2_description": "vietinės kopijos kituose prietaisuose. Tai apima pagrindinius failus ir jų vietines kopijas.",
"backup_onboarding_3_description": "viso jūsų duomenų kopijų, įskaitant originalius failus. Tai apima 1 išorinę ir 2 vietines kopijas.",
"backup_onboarding_description": "Jūsų duomenų apsaugojimui rekomenduojama <backblaze-link>3-2-1 atsarginės kopijos strategija</backblaze-link> . Jūs turėtumėte saugoti įkeltų nuotraukų/video bei Immich duomenų bazės kopijas išsamiam atsarginių kopijų sprendimui.",
"backup_onboarding_footer": "Daugiau informacijos apie „Immich“ atsarginių kopijų kūrimą rasite <link>dokumentacijoje</link>.",
"backup_onboarding_parts_title": "3-2-1 atsarginė kopija apima:",
"backup_onboarding_title": "Atsarginės kopijos",
@@ -75,7 +82,7 @@
"image_format_description": "WebP sukuria mažesnius failus nei JPEG, tačiau lėčiau juos apdoroja.",
"image_fullsize_description": "Pilno dydžio nuotrauka be meta duomenų naudojama priartinus",
"image_fullsize_enabled": "Įgalinti pilno dydžio nuotraukų generavimą",
"image_fullsize_enabled_description": "Generuoti viso dydžio vaizdą neinternetui pritaikytiems formatams. Kai įjungta parinktis „Pirmenybė įterptai peržiūrai“, įterptosios peržiūros naudojamos tiesiogiai be konvertavimo. Tai neturi įtakos internetui pritaikytiems formatams, pvz., JPEG",
"image_fullsize_enabled_description": "Generuoti viso dydžio vaizdą naršyklėms nepritaikytiems formatams. Kai įjungta parinktis „Pirmenybė įterptai peržiūrai“, įterptosios peržiūros naudojamos tiesiogiai be konvertavimo. Tai neturi įtakos internetui pritaikytiems formatams, pvz., JPEG.",
"image_fullsize_quality_description": "Pilno dydžio nuotraukų kokybė 1-100. Didesnė yra geresnė, tačiau sukuria didesniu failus.",
"image_fullsize_title": "Pilno dydžio nuotraukų Nustatymai",
"image_prefer_embedded_preview": "Pageidautinai rodyti įterptą peržiūrą",
@@ -99,8 +106,8 @@
"job_settings": "Užduočių nustatymai",
"job_settings_description": "Keisti užduočių lygiagretumą",
"job_status": "Užduočių būsenos",
"jobs_delayed": "{jobCount, plural, other {# delayed}}",
"jobs_failed": "{jobCount, plural, other {# failed}}",
"jobs_delayed": "{jobCount, plural, one {# atidėtas} few {# atidėti} other {# atidėtų}}",
"jobs_failed": "{jobCount, plural, other {# nepavyko}}",
"library_created": "Sukurta biblioteka: {library}",
"library_deleted": "Biblioteka ištrinta",
"library_import_path_description": "Nurodykite aplanką, kurį norite importuoti. Šiame aplanke, įskaitant poaplankius, bus nuskaityti vaizdai ir vaizdo įrašai.",
@@ -165,7 +172,7 @@
"metadata_extraction_job": "Metaduomenų nuskaitymas",
"metadata_extraction_job_description": "Kiekvieno bibliotekos elemento metaduomenų nuskaitymas, tokių kaip GPS koordinatės, veidai ar rezoliucija",
"metadata_faces_import_setting": "Įjungti veidų importą",
"metadata_faces_import_setting_description": "Importuoti veidus iš vaizdo EXIF duomenų ir papildomų failų",
"metadata_faces_import_setting_description": "Importuoti veidus iš vaizdo EXIF duomenų ir susietų failų",
"metadata_settings": "Metaduomenų nustatymai",
"metadata_settings_description": "Tvarkyti metaduomenų nustatymus",
"migration_job": "Tvarkymas",
@@ -182,6 +189,8 @@
"nightly_tasks_settings_description": "Valdyti naktines užduotis",
"nightly_tasks_start_time_setting": "Pradžios laikas",
"nightly_tasks_start_time_setting_description": "Laikas kada serveris pradės vykdyti naktines užduotis",
"nightly_tasks_sync_quota_usage_setting": "Sinchronizuoti kvotos naudojimą",
"nightly_tasks_sync_quota_usage_setting_description": "Atnaujinti vartotojo vietos kvotą remiantis dabartiniu vartojimu",
"no_paths_added": "Keliai nepridėti",
"no_pattern_added": "Šablonas nepridėtas",
"note_apply_storage_label_previous_assets": "Pastaba: norėdami pritaikyti Saugyklos Žymą seniau įkeltiems ištekliams, paleiskite",
@@ -303,29 +312,72 @@
"transcoding_codecs_learn_more": "Sužinoti daugiau apie naudojamą terminologiją, naudokite FFmpeg dokumentaciją <h264-link>H.264 codec</h264-link>, <hevc-link>HEVC codec</hevc-link> and <vp9-link>VP9 codec</vp9-link>.",
"transcoding_constant_quality_mode": "Pastovios kokybės režimas",
"transcoding_constant_quality_mode_description": "ICQ yra geriau nei CPQ, tačiau ne visi įrenginiai palaiko šį spartinimo būdą. Šis pasirinkimas būtų naudojamas kai nustatytas Kodavimas Pagal Kokybę. NVENC nepalaiko šio pasirinkimo todėl bus ignoruojamas.",
"transcoding_constant_rate_factor": "Pastovaus greičio faktorius (-crf)",
"transcoding_constant_rate_factor_description": "Video kokybės lygis. Tipinės reikšmės yra 23 jei H.264, 28 jei HVEC, 31 jei VP9, ir 35 jei AV1. Kuo mažesnis tuo kokybiškesnis tačiau didesni failai.",
"transcoding_disabled_description": "Nedaryti perkodavimo, įrašų peržiūra gali neveikti ant kai kūrių sąsajų",
"transcoding_encoding_options": "Užkodavimo parinktys",
"transcoding_encoding_options_description": "Nustatyti kodekus, rezoliuciją, kokybę ir kitas parinktis užkoduojamiems vaizdo įrašams",
"transcoding_hardware_acceleration": "Techninės įrangos spartinimas",
"transcoding_hardware_acceleration_description": "Eksperimentinis: greitesnis perkodavimas, bet galimai prastesne kokybe prie tos pačios bitų spartos",
"transcoding_hardware_decoding": "Aparatinis dekodavimas",
"transcoding_hardware_decoding_setting_description": "Įgalina visapusišką paspartinimą vietoje tik užkodavimo paspartinimo. Gali neveikti su kai kuriais vaizdo įrašais.",
"transcoding_max_b_frames": "Maksimaliai B-kadrų",
"transcoding_max_b_frames_description": "Didesnės reikšmės pagerina suspaudimo efektyvumą, bet sulėtina užkodavimą. Senesniuose prietaisuose gali būti nepalaikomas aparatinis spartinimas. 0 išjungia B-kadrus, o -1 nustato reikšmę automatiškai.",
"transcoding_max_bitrate": "Maksimalus bitų srautas",
"transcoding_max_bitrate_description": "Pasirenkant max bitrate galima pasiekti labiau nuspėjamą failų dydį su minimaliais kokybės praradimais. Prie 720p, tipinės reikšmės yra 2600 kbits/s jei BP9 ar HVEC, arba 4500 kbits/s jei H.264. Neveiksnus jei pasirenkamas 0.",
"transcoding_max_keyframe_interval": "Maksimalus raktinio kadro intervalas",
"transcoding_max_keyframe_interval_description": "Nustato maksimalų kadro atstumą tarp raktinių kadrų. Žemesnės reikšmės pablogina suspaudimo efektyvumą, bet pagerina prasukimo laiką ir gali pagerinti greito veiksmo scenų kokybę. 0 - nustato šią reikšmę automatiškai.",
"transcoding_optimal_description": "Vaizdo įrašai aukštesne nei tikslinė rezoliucija arba nepalaikomu formatu",
"transcoding_policy": "Transkodavimo politika",
"transcoding_policy_description": "Nustatyti kada vaizdo įrašas bus perkoduotas",
"transcoding_preferred_hardware_device": "Pageidaujamas aparatinės įrangos įrenginys",
"transcoding_preferred_hardware_device_description": "Galioja tik VAAPI ir QSV. Nustato dri mazgą aparatiniam perkodavimui.",
"transcoding_preset_preset": "Iš anksto nustatytas (-preset)",
"transcoding_preset_preset_description": "Kompresijos greitis. Siekiant tam tikro bitrate lėtesnis apdorojimas lems mažesnius failų dydžius ir padidins kokybę. VP9 ignoruos greičius virš \"gretesnis\" lygio.",
"transcoding_reference_frames": "Nuorodiniai kadrai",
"transcoding_reference_frames_description": "Kadrų, į kuriuos reikia remtis suspaudžiant duotą kadrą, skaičius. Aukštesnė reikšmė pagerina suspaudimo efektyvumą, bet sulėtina užkodavimą. 0 - nustato reikšmę automatiškai.",
"transcoding_required_description": "Tik nepalaikomo formato vaizdo įrašai",
"transcoding_settings": "Vaizdo įrašų perkodavimo nustatymai",
"transcoding_settings_description": "Valdyti kuriuos vaizdo įrašus perkoduoti ir kaip juos apdoroti",
"transcoding_target_resolution": "Skiriamoji geba",
"transcoding_target_resolution_description": "Didesnės skiriamosios gebos gali išsaugoti daugiau detalių, tačiau jas koduoti užtrunka ilgiau, failų dydžiai yra didesni ir gali sumažėti programos jautrumas.",
"transcoding_temporal_aq": "Laikinas adaptyvus kvantavimas",
"transcoding_temporal_aq_description": "Galioja tik NVENC. Pagerina detalių, mažo judesio scenų kokybę. Gali būti nepalaikoma senesnių įrenginių.",
"transcoding_threads": "Gijos",
"transcoding_threads_description": "Didesnės reikšmės pagreitina kodavimą, bet kol aktyvus palieka mažiau serverio resursų kitoms užduotims. Ši reikšmė negali būti didesnė už procesoriaus branduolių kiekį. Jei reikšmė 0, tai išnaudoja maksimaliai.",
"transcoding_tone_mapping": "Tonų atvaizdavimas",
"transcoding_tone_mapping_description": "Bandoma išsaugoti HDR vaizdo įrašų išvaizdą konvertuojant į SDR. Kiekvienas algoritmas taiko skirtingus kompromisus dėl spalvų, detalių ir šviesumo. Hable išsaugo detales, Mobius išsaugo spalvas, o Reinhard išsaugo šviesumą.",
"transcoding_transcode_policy": "Perkodavimo strategija",
"transcoding_transcode_policy_description": "Strategija, kada vaizdo įrašas turi būti perkoduotas. HDR vaizdo įrašai visada bus perkoduoti (išskyrus jei perkodavimas išjungtas).",
"transcoding_two_pass_encoding": "Dviejų perėjimų užkodavimas",
"transcoding_two_pass_encoding_setting_description": "Perkoduoti su dviem perėjimais, kad gauti geriau užkoduotą vaizdo įrašą. Kai maksimalus bitų srautas įjungtas (veikimui reikalaujamas H.264 ir HVEC), tada naudojamas bitų intervalas remiantis maksimaliu bitų srautu ir ignoruojamas CRF. Su VP9 gali būti naudojamas CRF, jei maksimalus bitų srautas yra išjungtas.",
"transcoding_video_codec": "Video kodekas",
"transcoding_video_codec_description": "VP9 turi didelį efektyvumą ir tinklo suderinamumą, bet užtrunka ilgiau perkoduojant. HVEC veikia panašiai, bet turi mažesnį tinklo suderinamumą. H.264 yra plačiai palaikomas ir greitai perkoduojamas, bet kuria didelius failus. AV1 yra efektyviausias kodekas, bet nepalaikomas senesnių prietaisų.",
"trash_enabled_description": "Įgalinti šiukšliadėžės funkcijas",
"trash_number_of_days": "Dienų skaičius",
"trash_number_of_days_description": "Kiek dienų bus laikomi elementai šiukšliadėžėje prieš galutinai juos ištrinant",
"trash_settings": "Šiukšliadėžės nustatymai",
"trash_settings_description": "Tvarkyti šiukšliadėžės nustatymus",
"unlink_all_oauth_accounts": "Atsieti visas OAuth paskyras",
"unlink_all_oauth_accounts_description": "Nepamirškite atsieti visas OAuth paskyras prieš migruojant pas naują tiekėją.",
"unlink_all_oauth_accounts_prompt": "Ar tikrai norite atsieti visas OAuth paskyras? Tai negrįžtama operacija kuri atstatys OAuth ID kiekvienam vartotojui.",
"user_cleanup_job": "Vartotojų išvalymas",
"user_delete_delay": "<b>{user}</b> paskyra ir elementai bus nustatyti galutiniam ištrynimui už {delay, plural, one {# dienos} other {# dienų}}.",
"user_delete_delay_settings": "Ištrynimo delsa",
"user_delete_delay_settings_description": "Skaičius dienų po ištrynimo kuomet vartotojo paskyrą ir susiję duomenys bus negražinamai ištrinti. Vartotojo Trynimo užduotis paleidžiama vidurnaktį ir tikrina kurie vartotojai gali būti trinami. Šio nustatymo pakeitimai bus naudojami sekančio užduoties paleidimo metu.",
"user_delete_delay_settings_description": "Skaičius dienų po ištrynimo kuomet naudotojo paskyra ir susiję duomenys bus negražinamai ištrinti. Naudotojo trynimo užduotis paleidžiama vidurnaktį ir tikrina kurie naudotojai gali būti trinami. Šio nustatymo pakeitimai bus naudojami sekančio užduoties paleidimo metu.",
"user_delete_immediately": "<b>{user}</b> paskyra ir elementai bus <b>nedelsiant</b> įtraukti galutiniam pašalinimui.",
"user_delete_immediately_checkbox": "Ištrinti naudotoją ir elementus nedelsiant",
"user_details": "Naudotojo duomenys",
"user_management": "Naudotojų valdymas",
"user_password_has_been_reset": "Naudotojo slaptažodis buvo iš naujo nustatytas:",
"user_password_reset_description": "Perduokite laikiną slaptažodį naudotojui ir informuokite, kad pasikeistų slaptažodį pirmo prisijungimo metu.",
"user_restore_description": "Naudotojo <b>{user}</b> paskyra bus atkurta.",
"user_restore_scheduled_removal": "Atkurti naudotoją - suplanuotas pašalinimas {date, date, long}",
"user_settings": "Naudotojo nustatymai",
"user_settings_description": "Valdyti naudotojo nustatymus",
"user_successfully_removed": "Naudotojas {email} sėkmingai pašalintas.",
"version_check_enabled_description": "Įgalinti versijų tikrinimą",
"version_check_implications": "Versijų tikrinimas reikalauja periodiškos komunikacijos su github.com",
"version_check_settings": "Versijos tikrinimas",
"version_check_settings_description": "Įjungti/išjungti naujos versijos pranešimus",
"video_conversion_job": "Vaizdo įrašų konvertavimas",
@@ -334,10 +386,36 @@
"admin_email": "Administratoriaus el. paštas",
"admin_password": "Administratoriaus slaptažodis",
"administration": "Administravimas",
"advanced": "Sudėtingesnis",
"advanced_settings_beta_timeline_subtitle": "Išbandykite naujos programos patirtį",
"advanced_settings_beta_timeline_title": "Beta laiko juosta",
"advanced_settings_enable_alternate_media_filter_subtitle": "Naudokite šį nustatymą medijos filtravimui sinchronizuojant remiantis alternatyviais kriterijais. Naudokite tik jei programa turi problemų su visų albumų aptikimu.",
"advanced_settings_enable_alternate_media_filter_title": "[EKSPERIMENTINIS] Naudokite alternatyvų įrenginio albumų sinchronizavimo filtrą",
"advanced_settings_log_level_title": "Žurnalo įrašų lygis: {level}",
"advanced_settings_prefer_remote_subtitle": "Kai kurie įrenginiai labai lėtai įkelia miniatiūras iš vietinių elementų. Aktyvuokite šį nustatymą, kad vietoje to užkrautumėte nuotolines nuotraukas.",
"advanced_settings_prefer_remote_title": "Teikti pirmenybę nuotolinėms nuotraukoms",
"advanced_settings_proxy_headers_subtitle": "Nustatykite tarpinio serverio antraštes kurias Immich siųs su kiekvienu užklausimu",
"advanced_settings_proxy_headers_title": "Tarpinio serverio antraštės",
"advanced_settings_readonly_mode_subtitle": "Įgalina tik skaitymo režimą kai nuotraukas galima tik žiūrėti, draudžiama pažymėti kelias, dalintis, transliuoti ar ištrinti. Įgalinkit/uždrauskit tik skaitymą per naudotojo avatar'ą iš pagrindinio lango",
"advanced_settings_readonly_mode_title": "Tik skaitymo režimas",
"advanced_settings_self_signed_ssl_subtitle": "Praleidžia SSL sertifikato tikrinimą serverio galutiniam taškui. Privaloma pačių pasirašytiems sertifikatams.",
"advanced_settings_self_signed_ssl_title": "Leisti pačių pasirašytus SSL sertifikatus",
"advanced_settings_sync_remote_deletions_subtitle": "Automatiškai ištrinti ar atkurti elementus įrenginyje, kai tie veiksmai atliekami naršyklėje",
"advanced_settings_sync_remote_deletions_title": "Sinchronizuoti nuotolinius ištrynimus [EKSPERIMENTINIS]",
"advanced_settings_tile_subtitle": "Pažangesni naudotojų nustatymai",
"advanced_settings_troubleshooting_subtitle": "Įgalinti papildomas galimybes trikčių šalinimui",
"advanced_settings_troubleshooting_title": "Trikčių šalinimas",
"age_months": "Amžius {months, plural, one {# mėnesis} few {# mėnesiai} other {# mėnesių}}",
"age_year_months": "Amžius 1 metai, {months, plural, one {# mėnesis} few {# mėnesiai} other {# mėnesių}}",
"age_years": "{years, plural, other {Amžius #}}",
"album_added": "Albumas pridėtas",
"album_added_notification_setting_description": "Gauti el. pašto pranešimą, kai būsite pridėtas prie bendrinamo albumo",
"album_cover_updated": "Albumo viršelis atnaujintas",
"album_delete_confirmation": "Ar tikrai norite ištrinti albumą {album}?",
"album_delete_confirmation_description": "Jei šiuo albumu dalijamasi, tai kiti naudotojai jo nebegalės pasiekti.",
"album_deleted": "Albumas ištrintas",
"album_info_card_backup_album_excluded": "neįtrauktas",
"album_info_card_backup_album_included": "įtrauktas",
"album_info_updated": "Albumo informacija atnaujinta",
"album_leave": "Palikti albumą?",
"album_leave_confirmation": "Ar tikrai norite palikti albumą {album}?",
@@ -345,16 +423,27 @@
"album_options": "Albumo parinktys",
"album_remove_user": "Pašalinti naudotoją?",
"album_remove_user_confirmation": "Ar tikrai norite pašalinti naudotoją {user}?",
"album_search_not_found": "Pagal jūsų paiešką albumų nerasta",
"album_share_no_users": "Atrodo, kad bendrinate šį albumą su visais naudotojais, arba neturite naudotojų, su kuriais galėtumėte bendrinti.",
"album_updated": "Albumas atnaujintas",
"album_updated_setting_description": "Gauti pranešimą el. paštu, kai bendrinamas albumas turi naujų elementų",
"album_user_left": "Paliko {album}",
"album_user_removed": "Pašalintas {user}",
"album_viewer_appbar_delete_confirm": "Ar tikrai norite ištrinti šį albumą iš savo paskyros?",
"album_viewer_appbar_share_err_delete": "Nepavyko ištrinti albumo",
"album_viewer_appbar_share_err_leave": "Nepavyko išeiti iš albumo",
"album_viewer_appbar_share_err_remove": "Kilo problemų pašalinant elementus iš albumo",
"album_viewer_appbar_share_err_title": "Nepavyko pakeisti albumo pavadinimą",
"album_viewer_appbar_share_leave": "Palikti albumą",
"album_viewer_appbar_share_to": "Dalintis su",
"album_viewer_page_share_add_users": "Pridėti naudotojų",
"album_with_link_access": "Tegul visi, turintys nuorodą, mato šio albumo nuotraukas ir žmones.",
"albums": "Albumai",
"albums_count": "{count, plural, one {# albumas} few {# albumai} other {# albumų}}",
"albums_default_sort_order": "Pradinė albumo rūšiavimo tvarka",
"albums_default_sort_order_description": "Pradinė elementų rūšiavimo tvarka kai kuriamas naujas albumas.",
"albums_feature_description": "Elementų rinkinys kuriuo galima dalintis su kitais naudotojais.",
"albums_on_device_count": "Albumų įrenginyje ({count})",
"all": "Visi",
"all_albums": "Visi albumai",
"all_people": "Visi žmonės",
@@ -363,51 +452,154 @@
"allow_edits": "Leisti redagavimus",
"allow_public_user_to_download": "Leisti viešam naudotojui atsisiųsti",
"allow_public_user_to_upload": "Leisti viešam naudotojui įkelti",
"alt_text_qr_code": "QR kodo paveiksliukas",
"anti_clockwise": "Prieš laikrodžio rodykles",
"api_key": "API raktas",
"api_key_description": "Ši reikšmė bus parodyta tik vieną kartą. Prašome nusikopijuoti prieš uždarant šį langą.",
"api_key_empty": "Jūsų API rakto pavadinimas netūrėtų būti tuščias",
"api_keys": "API raktai",
"app_bar_signout_dialog_content": "Ar tikrai norite atsijungti?",
"app_bar_signout_dialog_ok": "Taip",
"app_bar_signout_dialog_title": "Atsijungti",
"app_settings": "Programos nustatymai",
"appears_in": "Susiję",
"apply_count": "Taikyti ({count, number})",
"archive": "Archyvas",
"archive_action_prompt": "{count} pridėta į archyvą",
"archive_or_unarchive_photo": "Archyvuoti arba išarchyvuoti nuotrauką",
"archive_page_no_archived_assets": "Nerasta jokių archyvuotų elementų",
"archive_page_title": "Archyve ({count})",
"archive_size": "Archyvo dydis",
"archive_size_description": "Konfigūruoti archyvo dydį atsisiuntimams (GiB)",
"archived": "Archyvuota",
"archived_count": "{count, plural, other {# suarchyvuota}}",
"are_these_the_same_person": "Ar tai tas pats asmuo?",
"are_you_sure_to_do_this": "Ar tikrai norite tai daryti?",
"asset_action_delete_err_read_only": "Negalima ištrinti tik skaitom(o, ų) element(o, ų), praleidžiama",
"asset_action_share_err_offline": "Negalima užkrauti neprisijungusių elementų, praleidžiama",
"asset_added_to_album": "Pridėta į albumą",
"asset_adding_to_album": "Pridedama į albumą...",
"asset_adding_to_album": "Pridedama į albumą",
"asset_description_updated": "Elemento aprašymas buvo atnaujintas",
"asset_filename_is_offline": "Elementas {filename} nepasiekiamas",
"asset_has_unassigned_faces": "Elementas turi nepriskirtų veidų",
"asset_hashing": "Maišoma…",
"asset_list_group_by_sub_title": "Grupuoti pagal",
"asset_list_layout_settings_dynamic_layout_title": "Dinaminis išdėstymas",
"asset_list_layout_settings_group_automatically": "Automatiškai",
"asset_list_layout_settings_group_by": "Grupuoti elementus pagal",
"asset_list_layout_settings_group_by_month_day": "Mėnesis + diena",
"asset_list_layout_sub_title": "Išdėstymas",
"asset_list_settings_subtitle": "Nuotraukų tinklelio išdėstymo nustatymai",
"asset_list_settings_title": "Nuotraukų tinklelis",
"asset_offline": "Elementas nepasiekiamas",
"asset_offline_description": "Šis išorinis elementas neberandamas diske. Dėl pagalbos susisiekite su savo Immich administratoriumi.",
"asset_restored_successfully": "Elementas atkurtas sėkmingai",
"asset_skipped": "Praleista",
"asset_skipped_in_trash": "Šiukšliadėžėje",
"asset_uploaded": "Įkelta",
"asset_uploading": "Įkeliama...",
"asset_uploading": "Įkeliama",
"asset_viewer_settings_subtitle": "Tvarkykite savo galerijos peržiūros nustatymus",
"asset_viewer_settings_title": "Elementų peržiūra",
"assets": "Elementai",
"assets_added_count": "{count, plural, one {Pridėtas # elementas} few {Pridėti # elementai} other {Pridėta # elementų}}",
"assets_added_to_album_count": "Į albumą {count, plural, one {įtrauktas # elementas} few {įtraukti # elementai} other {įtraukta # elementų}}",
"assets_added_to_albums_count": "Pridėta {assetTotal, plural, one {# elementas} few {# elementai} other {# elementų}} į {albumTotal, plural, one {# albumą} few {# albumus} other {# albumų}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Elementas negali būti pridėtas} few {Elementai negali būti pridėti} other {Elementų negali būti pridėta}} į albumą",
"assets_cannot_be_added_to_albums": "{count, plural, one {Elementas negali būti pridėtas} few {Elementai negali būti pridėti} other {Elementų negali būti pridėta}} į nei vieną albumą",
"assets_count": "{count, plural, one {# elementas} few {# elementai} other {# elementų}}",
"assets_deleted_permanently": "{count} elementų ištrinta galutinai",
"assets_deleted_permanently_from_server": "{count} elementų ištrinta galutinai iš Immich serverio",
"assets_downloaded_failed": "{count, plural, one {Atsisiųstas # failas - {error} failas nepavyko} few {Atsisiųsti # failai - {error} failai nepavyko} other {Atsisiųsta # failų - {error} failų nepavyko}}",
"assets_downloaded_successfully": "{count, plural, one {Atsisiųstas # failas sėkmingai} few {Atsisiųsti # failai sėkmingai} other {Atsisiųsta # failų sėkmingai}}",
"assets_moved_to_trash_count": "{count, plural, one {# elementas perkeltas} few {# elementai perkelti} other {# elementų perkelta}} į šiukšliadėžę",
"assets_permanently_deleted_count": "{count, plural, one {# elementas ištrintas} few {# elementai ištrinti} other {# elementų ištrinta}} visam laikui",
"assets_removed_count": "{count, plural, one {Pašalintas # elementas} few {Pašalinti # elementai} other {Pašalinta # elementų}}",
"assets_removed_permanently_from_device": "{count} elementų pašalinta galutinai iš jūsų įrenginio",
"assets_restore_confirmation": "Ar tikrai norite atkurti visus šiukšliadėžėje esančius perkeltus elementus? Šio veiksmo atšaukti negalėsite! Pastaba: nepasiekiami elementai tokiu būdu atkurti nebus.",
"assets_restored_count": "{count, plural, one {Atkurtas # elementas} few {Atkurti # elementai} other {Atkurta # elementų}}",
"assets_restored_successfully": "{count} element(as, ai, ų) atkurta sėkmingai",
"assets_trashed": "{count} element(ai,ų,as) perkelta į šiukšliadėžę",
"assets_trashed_count": "Perkelta į šiukšliadėžę {count, plural, one {# elementas} few {# elementai} other {# elementų}}",
"assets_trashed_from_server": "{count} element(as, ai, ų) perkelta į šiukšliadėžę iš Immich serverio",
"assets_were_part_of_album_count": "{count, plural, one {# elementas} few {# elementai} other {# elementų}} jau prieš tai buvo albume",
"assets_were_part_of_albums_count": "{count, plural, one {Elementas } few {Elementai} other {Elementų}} jau buvo albumuose",
"authorized_devices": "Autorizuoti įrenginiai",
"automatic_endpoint_switching_subtitle": "Prisijungti vietoje per priskirtą Wi-Fi kai įmanoma ir naudoti alternatyvų prisijungimą visur kitur",
"automatic_endpoint_switching_title": "Automatinis URL perjungimas",
"autoplay_slideshow": "Automatiškai rodyti skaidrių demonstraciją",
"back": "Atgal",
"back_close_deselect": "Atgal, uždaryti arba atžymėti",
"background_location_permission": "Foninis vietovės leidimas",
"background_location_permission_content": "Veikiant fone tinklo perjungimui Immich privalo *visada* turėti prieigą prie tikslios vietovės, kad programa galėtų perskaityti Wi-Fi tinklo pavadinimą",
"backup": "Atsarginė kopija",
"backup_album_selection_page_albums_device": "Albumų įrenginyje ({count})",
"backup_album_selection_page_albums_tap": "Palieskite įtraukti, du kart palieskite neįtraukti",
"backup_album_selection_page_assets_scatter": "Elementai gali išsibarstyti per kelis albumus. Todėl albumai gali būti įtraukti arba neįtraukti per atsarginio kopijavimo procesą.",
"backup_album_selection_page_select_albums": "Pažymėti albumai",
"backup_album_selection_page_selection_info": "Pažymėjimo informacija",
"backup_album_selection_page_total_assets": "Viso unikalių elementų",
"backup_all": "Visi",
"backup_background_service_backup_failed_message": "Nepavyko sukurti atsarginių kopijų. Bandoma dar kartą…",
"backup_background_service_connection_failed_message": "Nepavyko prisijungti prie serverio. Bandoma dar kartą…",
"backup_background_service_current_upload_notification": "Įkeliamas {filename}",
"backup_background_service_default_notification": "Ieškoma naujų elementų…",
"backup_background_service_error_title": "Atsarginio kopijavimo klaida",
"backup_background_service_in_progress_notification": "Kuriama elementų atsarginė kopija…",
"backup_background_service_upload_failure_notification": "Nepavyko įkelti {filename}",
"backup_controller_page_background_wifi": "Only on WiFi",
"backup_controller_page_albums": "Atsarginės kopijos albumai",
"backup_controller_page_background_app_refresh_disabled_title": "Foninis programos atnaujinimas išjungtas",
"backup_controller_page_background_app_refresh_enable_button_text": "Eiti į nustatymus",
"backup_controller_page_background_battery_info_link": "Parodyk man kaip",
"backup_controller_page_background_battery_info_message": "Norint geriausių foninio atsarginio kopijavimo rezultatų, prašome išjungti akumuliatoriaus optimizavimą ribojantį foninį Immich veikimą.\n\nKadangi tai priklauso nuo įrenginio, prašome susirasti reikiamą informaciją pas įrenginio gamintoją.",
"backup_controller_page_background_battery_info_ok": "OK",
"backup_controller_page_background_battery_info_title": "Akumuliatoriaus optimizavimai",
"backup_controller_page_background_charging": "Tik kol kraunasi",
"backup_controller_page_background_configure_error": "Nepavyko sukonfigūruoti foninių paslaugų",
"backup_controller_page_background_delay": "Atidėti naujų elementų atsarginį kopijavimą: {duration}",
"backup_controller_page_background_description": "Įjunkite fonines paslaugas, kad galėtumėte automatiškai kurti atsargines kopijas neatidarant programos",
"backup_controller_page_background_is_off": "Automatinis atsarginis kopijavimas yra išjungtas",
"backup_controller_page_background_is_on": "Automatinis atsarginis kopijavimas yra įjungtas",
"backup_controller_page_background_turn_off": "Išjungti fonines paslaugas",
"backup_controller_page_background_turn_on": "Įjungti fonines paslaugas",
"backup_controller_page_background_wifi": "Tik su Wi-Fi",
"backup_controller_page_backup": "Atsarginis kopijavimas",
"backup_controller_page_backup_selected": "Pasirinkta: ",
"backup_controller_page_backup_sub": "Perkeltos nuotraukos ir vaizdo įrašai",
"backup_controller_page_created": "Sukurta: {date}",
"backup_controller_page_desc_backup": "Įjunkite foninį atsarginį kopijavimą, kad būtų automatiškai perkeliami nauji elementai į serverį kai atidaroma programa.",
"backup_controller_page_excluded": "Neįtraukta: ",
"backup_controller_page_failed": "Nepavyko ({count})",
"backup_controller_page_filename": "Failo pavadinimas: {filename}[{size}]",
"backup_controller_page_id": "ID: {id}",
"backup_controller_page_info": "Atsarginio kopijavimo informacija",
"backup_controller_page_none_selected": "Niekas nepasirinkta",
"backup_controller_page_remainder": "Dar liko",
"backup_controller_page_remainder_sub": "Likusios pasirinktos atsarginio kopijavimo nuotraukos ir vaizdo įrašai",
"backup_controller_page_server_storage": "Serverio saugykla",
"backup_controller_page_start_backup": "Pradėti atsarginį kopijavimą",
"backup_controller_page_status_off": "Automatinis foninis atsarginis kopijavimas yra išjungtas",
"backup_controller_page_status_on": "Automatinis foninis atsarginis kopijavimas yra įjungtas",
"backup_controller_page_storage_format": "{used} iš {total} panaudota",
"backup_controller_page_to_backup": "Albumai kurių atsarginis kopijavimas bus atliktas",
"backup_controller_page_total_sub": "Visos unikalios nuotraukos ir video įrašai iš pažymėtų albumų",
"backup_controller_page_turn_off": "Išjungti foninį atsarginį kopijavimą",
"backup_controller_page_turn_on": "Įjungti foninį atsarginį kopijavimą",
"backup_controller_page_uploading_file_info": "Įkeliama failo info",
"backup_err_only_album": "Negalima pašalinti vienintelio albumo",
"backup_info_card_assets": "elementai",
"backup_manual_cancelled": "Atšaukta",
"backup_manual_in_progress": "Jau įkeliama, bandykite dar kartą vėliau",
"backup_manual_success": "Pavyko",
"backup_manual_title": "Įkėlimo būklė",
"backup_options": "Atsarginio kopijavimo nustatymai",
"backup_options_page_title": "Atsarginio kopijavimo nustatymai",
"backup_setting_subtitle": "Tvarkyti foninio ir priekinio plano įkėlimo nustatymus",
"backup_settings_subtitle": "Tvarkyti įkėlimo nustatymus",
"backward": "Atgalinis",
"biometric_auth_enabled": "Biometrinis autentifikavimas įgalintas",
"biometric_locked_out": "Jūs esate užblokuotas biometrinio autentifikavimo funkcijai",
"biometric_no_options": "Nėra galimų biometrinių nustatymų",
"biometric_not_available": "Biometrinis autentifikavimas šiame įrenginyje negalimas",
"birthdate_saved": "Sėkmingai išsaugota gimimo data",
"birthdate_set_description": "Gimimo data naudojama apskaičiuoti asmens amžių nuotraukos darymo metu.",
"blurred_background": "Neryškus fonas",
@@ -416,42 +608,104 @@
"bulk_keep_duplicates_confirmation": "Ar tikrai norite palikti visus {count, plural, one {# besidubliuojantį elementą} few {# besidubliuojančius elementus} other {# besidubliuojančių elementų}}? Tokiu būdu nieko netrinant bus sutvarkytos visos dublikatų grupės.",
"bulk_trash_duplicates_confirmation": "Ar tikrai norite perkelti į šiukšliadėžę visus {count, plural, one {# besidubliuojantį elementą} few {# besidubliuojančius elementus} other {# besidubliuojančių elementų}}? Bus paliktas didžiausias kiekvienos grupės elementas ir į šiukšliadėžę perkelti kiti besidubliuojantys elementai.",
"buy": "Įsigyti Immich",
"cache_settings_clear_cache_button": "Išvalyti laikiną talpyklą",
"cache_settings_clear_cache_button_title": "Išvalo programos laikiną talpyklą. Tai gali smarkiai paveikti programos greitį, kol bus sukurta nauja laikinoji talpykla.",
"cache_settings_duplicated_assets_clear_button": "IŠVALYTI",
"cache_settings_duplicated_assets_subtitle": "Nuotraukos ir video įrašai kurie yra programos ignoruojamų sąraše",
"cache_settings_duplicated_assets_title": "Sudubliuoti elementai ({count})",
"cache_settings_statistics_album": "Bibliotekos miniatiūros",
"cache_settings_statistics_full": "Pilno dydžio nuotraukos",
"cache_settings_statistics_shared": "Bendrinamų albumų miniatiūros",
"cache_settings_statistics_thumbnail": "Miniatiūros",
"cache_settings_statistics_title": "Laikinos talpyklos naudojimas",
"cache_settings_subtitle": "Valdykite Immich mobiliosios programos laikinosios talpyklos elgesį",
"cache_settings_tile_subtitle": "Valdykite vietinės talpyklos elgesį",
"cache_settings_tile_title": "Vietinė talpykla",
"cache_settings_title": "Laikinosios talpyklos nustatymai",
"camera": "Fotoaparatas",
"camera_brand": "Fotoaparato prekės ženklas",
"camera_model": "Fotoaparato modelis",
"cancel": "Atšaukti",
"cancel_search": "Atšaukti paiešką",
"canceled": "Atšaukta",
"canceling": "Atšaukiama",
"cannot_merge_people": "Negalima sujungti asmenų",
"cannot_undo_this_action": "Jūs negalėsite atkurti po šio veiksmo!",
"cannot_update_the_description": "Negalima atnaujinti aprašymo",
"cast": "Transliuoti",
"cast_description": "Valdyti galimas transliavimo kryptis",
"change_date": "Pakeisti datą",
"change_description": "Pakeisti aprašymus",
"change_display_order": "Pakeisti atvaizdavimo tvarką",
"change_expiration_time": "Pakeisti galiojimo trukmę",
"change_location": "Pakeisti vietovę",
"change_name": "Pakeisti vardą",
"change_name_successfully": "Vardas pakeistas sėkmingai",
"change_password": "Pakeisti slaptažodį",
"change_password_description": "Tai arba pirmas kartas, kai jungiatės prie sistemos, arba buvo pateikta užklausa pakeisti jūsų slaptažodį. Prašome įvesti naują slaptažodį žemiau.",
"change_password_form_confirm_password": "Patvirtinti slaptažodį",
"change_password_form_description": "Labas {name},\n\nTai yra pirmas kartas kai tu prisijungei prie sistemos arba buvo prašymas pakeisti slaptažodį. Prašome įvesti naują slaptažodį žemiau.",
"change_password_form_new_password": "Naujas slaptažodis",
"change_password_form_password_mismatch": "Slaptažodžiai nesutampa",
"change_password_form_reenter_new_password": "Pakartotinai įveskite naują slaptažodį",
"change_pin_code": "Pakeisti PIN kodą",
"change_your_password": "Pakeisti slaptažodį",
"changed_visibility_successfully": "Matomumas pakeistas sėkmingai",
"check_corrupt_asset_backup": "Patikrinti sugadintų elementų atsarginę kopiją",
"check_corrupt_asset_backup_button": "Atlikti patikrinimą",
"check_corrupt_asset_backup_description": "Paleiskite šį patikrinimą tik per Wi-Fi ir tik kai visi elementai buvo perkopijuoti. Ši procedūra užtruks kelias minutes.",
"check_logs": "Tikrinti žurnalus",
"choose_matching_people_to_merge": "Pasirinkite atitinkančius žmones sujungimui",
"city": "Miestas",
"clear": "Išvalyti",
"clear_all": "Išvalyti viską",
"clear_all_recent_searches": "Išvalyti visas naujausias paieškas",
"clear_file_cache": "Išvalyti failų laikiną talpyklą",
"clear_message": "Išvalyti pranešimą",
"clear_value": "Išvalyti reikšmę",
"client_cert_dialog_msg_confirm": "OK",
"client_cert_enter_password": "Įveskite slaptažodį",
"client_cert_import": "Importuoti",
"client_cert_import_success_msg": "Kliento sertifikatas yra importuotas",
"client_cert_invalid_msg": "Netinkamas sertifikato failas arba neteisingas slaptažodis",
"client_cert_remove_msg": "Kliento sertifikatas yra pašalintas",
"client_cert_subtitle": "Palaikomi tik PKCS12 (.p12, .pfx) formatai. Sertifikato importavimas/pašalinimas galimas tik prieš prisijungimą",
"client_cert_title": "SSL kliento sertifikatas",
"clockwise": "Pagal laikrodžio rodykles",
"close": "Uždaryti",
"collapse": "Suskleisti",
"collapse_all": "Suskleisti viską",
"color": "Spalva",
"color_theme": "Temos spalva",
"comment_deleted": "Komentaras ištrintas",
"comment_options": "Komentarų parinktys",
"comments_and_likes": "Komentarai ir patiktukai",
"comments_are_disabled": "Komentarai yra išjungti",
"common_create_new_album": "Sukurti naują albumą",
"common_server_error": "Prašome patikrinti tinklo prisijungimą ir įsitikinti, kad serveris pasiekiamas ir programos/serverio versija sutampa.",
"completed": "Atlikta",
"confirm": "Patvirtinti",
"confirm_admin_password": "Patvirtinti administratoriaus slaptažodį",
"confirm_delete_face": "Ar tikrai norite ištrinti {name} veidą iš elementų?",
"confirm_delete_shared_link": "Ar tikrai norite ištrinti šią bendrinimo nuorodą?",
"confirm_keep_this_delete_others": "Visi kiti elementai iš krūvos bus ištrinti išskyrus šį elementą. Ar tikrai norite tęsti?",
"confirm_new_pin_code": "Patvirtinkite naują PIN kodą",
"confirm_password": "Patvirtinti slaptažodį",
"confirm_tag_face": "Ar norite priskirti šį veidą kaip {name}?",
"confirm_tag_face_unnamed": "Ar norite priskirti šį veidą?",
"connected_device": "Prijungtas įrenginys",
"connected_to": "Prisijungta prie",
"contain": "Tilpti",
"context": "Kontekstas",
"continue": "Tęsti",
"control_bottom_app_bar_create_new_album": "Sukurti naują albumą",
"control_bottom_app_bar_delete_from_immich": "Ištrinti iš Immich",
"control_bottom_app_bar_delete_from_local": "Ištrinti iš įrenginio",
"control_bottom_app_bar_edit_location": "Redaguoti vietovę",
"control_bottom_app_bar_edit_time": "Redaguoti datą ir laiką",
"control_bottom_app_bar_share_link": "Dalintis nuoroda",
"control_bottom_app_bar_share_to": "Dalintis su",
"control_bottom_app_bar_trash_from_immich": "Perkelti į šiukšliadėžę",
"copied_image_to_clipboard": "Nuotrauka nukopijuota į iškarpinę.",
"copied_to_clipboard": "Nukopijuota į iškapinę!",
"copy_error": "Kopijavimo klaida",
@@ -462,6 +716,8 @@
"copy_password": "Kopijuoti slaptažodį",
"copy_to_clipboard": "Kopijuoti į iškarpinę",
"country": "Šalis",
"cover": "Užpildyti",
"covers": "Viršeliai",
"create": "Sukurti",
"create_album": "Sukurti albumą",
"create_album_page_untitled": "Be pavadinimo",
@@ -469,57 +725,115 @@
"create_link": "Sukurti nuorodą",
"create_link_to_share": "Sukurti bendrinimo nuorodą",
"create_link_to_share_description": "Leisti bet kam su nuoroda matyti pažymėtą(-as) nuotrauką(-as)",
"create_new": "SUKURTI NAUJĄ",
"create_new_person": "Sukurti naują žmogų",
"create_new_person_hint": "Priskirti pasirinktus elementus naujam žmogui",
"create_new_user": "Sukurti naują varotoją",
"create_shared_album_page_share_add_assets": "PRIDĖTI ELEMENTŲ",
"create_shared_album_page_share_select_photos": "Pažymėti nuotraukas",
"create_shared_link": "Sukurti dalijimosi nuorodą",
"create_tag": "Sukurti žymą",
"create_tag_description": "Sukurti naują žymą. Įdėtinėms žymoms įveskite pilną kelią, įskaitant pasviruosius brūkšnius.",
"create_user": "Sukurti naudotoją",
"created": "Sukurta",
"created_at": "Sukurta",
"crop": "Apkirpti",
"curated_object_page_title": "Daiktai",
"current_device": "Dabartinis įrenginys",
"current_pin_code": "Dabartinis PIN kodas",
"current_server_address": "Dabartinis serverio adresas",
"custom_locale": "Pasirinktinė vietovė",
"custom_locale_description": "Formatuoti datas ir skaičius pagal kalbą ir regioną",
"custom_url": "Pasirinktinis URL",
"daily_title_text_date": "E, MMM dd",
"daily_title_text_date_year": "E, MMM dd, yyyy",
"dark": "Tamsi",
"dark_theme": "Perjungti tamsią temą",
"date_after": "Data po",
"date_and_time": "Data ir laikas",
"date_before": "Data prieš",
"date_format": "E, LLL d, y • h:mm",
"date_of_birth_saved": "Gimimo data sėkmingai išsaugota",
"date_range": "Datų intervalas",
"day": "Diena",
"days": "Dienų",
"deduplicate_all": "Šalinti visus dublikatus",
"deduplication_criteria_1": "Failo dydis baitais",
"deduplication_criteria_2": "EXIF metaduomenų įrašų skaičius",
"deduplication_info": "Dublikatų šalinimo informacija",
"deduplication_info_description": "Automatinis elementų parinkimas ir masinis dublikatų šalinimas atliekamas atsižvelgiant į:",
"default_locale": "Pradinė vietovė",
"default_locale_description": "Formatuoti datas ir skaičius pagal jūsų naršyklės lokalę",
"delete": "Ištrinti",
"delete_action_confirmation_message": "Ar tikrai norite ištrinti šį elementą? Šis veiksmas perkels elementą į serverio šiukšliadėžę ir paklaus ar norite ištrinti vietiniame įrenginyje",
"delete_action_prompt": "{count} ištrinta",
"delete_album": "Ištrinti albumą",
"delete_api_key_prompt": "Ar tikrai norite ištrinti šį API raktą?",
"delete_dialog_alert": "Šie elementai bus galutinai ištrinti iš Immich ir iš jūsų įrenginio",
"delete_dialog_alert_local": "Šie elementai bus galutinai pašalinti iš jūsų įrenginio, bet bus prieinami Immich serveryje",
"delete_dialog_alert_local_non_backed_up": "Kai kurie elementai be Immich atsarginės kopijos ir bus galutinai pašalinti iš jūsų įrenginio",
"delete_dialog_alert_remote": "Šie elementai bus galutinai ištrinti iš Immich serverio",
"delete_dialog_ok_force": "Vis tiek ištrinti",
"delete_dialog_title": "Ištrinti galutinai",
"delete_duplicates_confirmation": "Ar tikrai norite visam laikui ištrinti šiuos dublikatus?",
"delete_face": "Ištrinti veidą",
"delete_key": "Ištrinti raktą",
"delete_library": "Ištrinti biblioteką",
"delete_link": "Ištrinti nuorodą",
"delete_local_action_prompt": "{count} ištrinti vietiniame įrenginyje",
"delete_local_dialog_ok_backed_up_only": "Ištrinti tik turinčius atsarginę kopiją",
"delete_local_dialog_ok_force": "Vis tiek ištrinti",
"delete_others": "Ištrinti kitus",
"delete_permanently": "Ištrinti galutinai",
"delete_permanently_action_prompt": "{count} ištrinta galutinai",
"delete_shared_link": "Ištrinti bendrinimo nuorodą",
"delete_shared_link_dialog_title": "Ištrinti dalijimosi nuorodą",
"delete_tag": "Ištrinti žymą",
"delete_tag_confirmation_prompt": "Ar tikrai norite ištrinti žymą {tagName}?",
"delete_user": "Ištrinti naudotoją",
"deleted_shared_link": "Bendrinimo nuoroda ištrinta",
"deletes_missing_assets": "Ištrinti diske trūkstamus elementus",
"description": "Aprašymas",
"description_input_hint_text": "Pridėti aprašymą...",
"description_input_submit_error": "Klaida atnaujinant aprašymą, pasitikrinkite žurnalą norint detalesnės informacijos",
"deselect_all": "Atžymėti visus",
"details": "Detalės",
"direction": "Kryptis",
"disabled": "Išjungta",
"disallow_edits": "Neleisti redaguoti",
"discord": "Discord",
"discover": "Atrasti",
"discovered_devices": "Aptikti įrenginiai",
"dismiss_all_errors": "Nepaisyti visų klaidų",
"dismiss_error": "Nepaisyti klaidos",
"display_options": "Atvaizdavimo parinktys",
"display_order": "Atvaizdavimo tvarka",
"display_original_photos": "Rodyti originalias nuotraukas",
"display_original_photos_setting_description": "Pirmenybė rodyti originalią nuotrauką vietoje miniatiūros kai originalo elementas yra palaikomas naršyklės. Tai gali lemti lėtesnį nuotraukos rodymo greitį.",
"do_not_show_again": "Daugiau nerodyti šio pranešimo",
"documentation": "Dokumentacija",
"done": "Atlikta",
"download": "Atsisiųsti",
"download_action_prompt": "Atsisiunčiami {count} elementai",
"download_canceled": "Atsisiuntimas atšauktas",
"download_complete": "Atsisiuntimas pabaigtas",
"download_enqueue": "Atsisiuntimai įtraukti į eilę",
"download_error": "Atsisiuntimo klaida",
"download_failed": "Nepavyko parsisiųsti",
"download_finished": "Atsisiuntimas pabaigtas",
"download_include_embedded_motion_videos": "Įterpti vaizdo įrašai",
"download_include_embedded_motion_videos_description": "Pridėti prie judesio nuotraukų įterptus video kaip atskirą failą",
"download_notfound": "Atsisiuntimas nerastas",
"download_paused": "Atsisiuntimas pristabdytas",
"download_settings": "Atsisiųsti",
"download_settings_description": "Tvarkyti elementų atsisiuntimo nustatymus",
"download_started": "Atsisiuntimas pradėtas",
"download_sucess": "Atsisiuntimas pavyko",
"download_sucess_android": "Medija buvo atsiųsta į DCIM/Immich",
"download_waiting_to_retry": "Laukiama bandymo iš naujo",
"downloading": "Siunčiama",
"downloading_asset_filename": "Parsisiunčiamas resursas {filename}",
"downloading_media": "Atsisiunčiama medija",
"drop_files_to_upload": "Užkelkite failus bet kurioje vietoje kad įkeltumėte",
"duplicates": "Dublikatai",
"duplicates_description": "Sutvarkykite kiekvieną elementų grupę nurodydami elementus, kurie yra dublikatai (jei tokių yra)",
@@ -527,8 +841,14 @@
"edit": "Redaguoti",
"edit_album": "Redaguoti albumą",
"edit_avatar": "Redaguoti avatarą",
"edit_birthday": "Redaguoti gimtadienį",
"edit_date": "Redaguoti datą",
"edit_date_and_time": "Redaguoti datą ir laiką",
"edit_date_and_time_action_prompt": "{count} data ir laikas redaguotas",
"edit_date_and_time_by_offset": "Keisti datą pagal poslinkį",
"edit_date_and_time_by_offset_interval": "Naujas datos intervalas: {from} - {to}",
"edit_description": "Redaguoti aprašymą",
"edit_description_prompt": "Prašome pasirinkti naują aprašymą:",
"edit_exclusion_pattern": "Redaguoti išimčių šabloną",
"edit_faces": "Redaguoti veidus",
"edit_import_path": "Redaguoti importavimo kelią",
@@ -536,41 +856,79 @@
"edit_key": "Redaguoti raktą",
"edit_link": "Redaguoti nuorodą",
"edit_location": "Redaguoti vietovę",
"edit_location_action_prompt": "{count} vietovės pakeistos",
"edit_location_dialog_title": "Vietovė",
"edit_name": "Redaguoti vardą",
"edit_people": "Redaguoti žmones",
"edit_tag": "Redaguoti žymą",
"edit_title": "Redaguoti antraštę",
"edit_user": "Redaguoti naudotoją",
"edited": "Redaguota",
"editor": "Redaktorius",
"editor_close_without_save_prompt": "Pakeitimai nebus išsaugoti",
"editor_close_without_save_title": "Uždaryti redaktorių?",
"editor_crop_tool_h2_aspect_ratios": "Vaizdo santykis",
"editor_crop_tool_h2_rotation": "Pasukimas",
"email": "El. paštas",
"email_notifications": "El. pašto pranešimai",
"empty_folder": "Šis katalogas yra tuščias",
"empty_trash": "Ištuštinti šiukšliadėžę",
"empty_trash_confirmation": "Ar tikrai norite ištuštinti šiukšliadėžę? Tai galutinai pašalins elementus iš Immich.\nJūs negalėsite atkurti šio veiksmo!",
"enable": "Įgalinti",
"enable_backup": "Įgalinti atsargines kopijas",
"enable_biometric_auth_description": "Įveskite savo PIN kodą biometrinės autentifikacijos įjungimui",
"enabled": "Įgalintas",
"end_date": "Pabaigos data",
"enter_wifi_name": "Enter WiFi name",
"enqueued": "Įtraukta į eilę",
"enter_wifi_name": "Įveskite Wi-Fi pavadinimą",
"enter_your_pin_code": "Įveskite savo PIN kodą",
"enter_your_pin_code_subtitle": "Įveskite savo PIN kodą, kad pasiektumėte užrakintą aplanką",
"error": "Klaida",
"error_change_sort_album": "Nepavyko pakeisti albumo rūšiavimo tvarkos",
"error_delete_face": "Klaida trinant veidą iš elementų",
"error_loading_image": "Klaida įkeliant vaizdą",
"error_saving_image": "Klaida: {error}",
"error_tag_face_bounding_box": "Klaida aprašant veidą - nepavyko gauti veido vietos koordinačių",
"error_title": "Klaida - Kažkas nutiko ne taip",
"errors": {
"cannot_navigate_next_asset": "Negalima pereiti prie sekančio elemento",
"cannot_navigate_previous_asset": "Negalima pereiti prie buvusio elemento",
"cant_apply_changes": "Negalima taikyti pakeitimų",
"cant_change_activity": "Negalima {enabled, select, true {išjungti} other {įjungti}} veiklos",
"cant_change_asset_favorite": "Elementui negalima pakeisti mėgstamiausio",
"cant_change_metadata_assets_count": "Negalima pakeisti {count, plural, one {# elemento} other {# elementų}} metadata",
"cant_get_faces": "Nepavyko gauti veidus",
"cant_get_number_of_comments": "Nepavyko gauti komentarų skaičiaus",
"cant_search_people": "Negalima ieškoti žmonių",
"cant_search_places": "Negalima ieškoti vietovių",
"error_adding_assets_to_album": "Klaida pridedant elementus į albumą",
"error_adding_users_to_album": "Klaida pridedant naudotojus prie albumo",
"error_deleting_shared_user": "Klaida trinant pasidalintą naudotoją",
"error_downloading": "Klaida atsisiunčiant {filename}",
"error_hiding_buy_button": "Klaida slepiant pirkimo mygtuką",
"error_removing_assets_from_album": "Klaida šalinant elementus iš albumo, patikrinkite konsolę dėl išsamesnės informacijos",
"error_selecting_all_assets": "Klaida pasirenkant visus elementus",
"exclusion_pattern_already_exists": "Šis išimčių šablonas jau egzistuoja.",
"failed_to_create_album": "Nepavyko sukurti albumo",
"failed_to_create_shared_link": "Nepavyko sukurti bendrinimo nuorodos",
"failed_to_edit_shared_link": "Nepavyko redaguoti bendrinimo nuorodos",
"failed_to_get_people": "Nepavyko gauti žmonių",
"failed_to_keep_this_delete_others": "Nepavyko palikti šį elementą ir ištrinti kitus elementus",
"failed_to_load_asset": "Nepavyko užkrauti elemento",
"failed_to_load_assets": "Nepavyko užrauti elementų",
"failed_to_load_notifications": "Nepavyko užkrauti pranešimų",
"failed_to_load_people": "Nepavyko užkrauti žmonių",
"failed_to_remove_product_key": "Nepavyko pašalinti produkto rakto",
"failed_to_reset_pin_code": "Nepavyko atkurti PIN kodo",
"failed_to_stack_assets": "Nepavyko sugrupuoti elementų",
"failed_to_unstack_assets": "Nepavyko išgrupuoti elementų",
"failed_to_update_notification_status": "Nepavyko atnaujinti pranešimo statuso",
"import_path_already_exists": "Šis importavimo kelias jau egzistuoja.",
"incorrect_email_or_password": "Neteisingas el. pašto adresas arba slaptažodis",
"paths_validation_failed": "Nepavyko {paths, plural, one {# kelio} other {# kelių}} patvirtinimas",
"profile_picture_transparent_pixels": "Profilio nuotrauka negali turėti permatomų pikselių. Prašome priartinti ir/arba perkelkite nuotrauką.",
"quota_higher_than_disk_size": "Nustatyta kvota, viršija disko dydį",
"something_went_wrong": "Kažkas nepavyko",
"unable_to_add_album_users": "Nepavyksta pridėti naudotojų prie albumo",
"unable_to_add_assets_to_shared_link": "Nepavyko į bendrinimo nuorodą pridėti elementų",
"unable_to_add_comment": "Nepavyksta pridėti komentaro",
@@ -578,11 +936,15 @@
"unable_to_add_import_path": "Nepavyksta pridėti importavimo kelio",
"unable_to_add_partners": "Nepavyksta pridėti partnerių",
"unable_to_add_remove_archive": "Nepavyko {archived, select, true {ištraukti iš} other {pridėti prie}} arcyhvo",
"unable_to_add_remove_favorites": "Nepavyko {favorite, select, true {įtraukti elemento į mėgstamiausius} other {pašalinti elemento iš mėgstamiausių}}",
"unable_to_archive_unarchive": "Nepavyko {archived, select, true {archyvuoti} other {išarchyvuoti}}",
"unable_to_change_album_user_role": "Nepavyksta pakeisti albumo naudotojo rolės",
"unable_to_change_date": "Negalima pakeisti datos",
"unable_to_change_description": "Nepavyko pakeisti aprašymo",
"unable_to_change_favorite": "Nepavyko pakeisti elementui mėgstamiausio",
"unable_to_change_location": "Negalima pakeisti vietos",
"unable_to_change_password": "Negalima pakeisti slaptažodžio",
"unable_to_change_visibility": "Nepavyko pakeisti matomumo {count, plural, one {# asmeniui} few {#asmenims} other {# asmenų}}",
"unable_to_complete_oauth_login": "Nepavyko prisijungti su OAuth",
"unable_to_connect": "Nepavyko prisijungti",
"unable_to_copy_to_clipboard": "Negalima kopijuoti į iškarpinę, įsitikinkite, kad prie puslapio prieinate per https",
@@ -591,6 +953,8 @@
"unable_to_create_library": "Nepavyko sukurti bibliotekos",
"unable_to_create_user": "Nepavyko sukurti naudotojo",
"unable_to_delete_album": "Nepavyksta ištrinti albumo",
"unable_to_delete_asset": "Nepavyko ištrinti elemento",
"unable_to_delete_assets": "Klaida trinant elementus",
"unable_to_delete_exclusion_pattern": "Nepavyksta ištrinti išimčių šablono",
"unable_to_delete_import_path": "Nepavyksta ištrinti importavimo kelio",
"unable_to_delete_shared_link": "Nepavyko ištrinti bendrinimo nuorodos",
@@ -598,22 +962,37 @@
"unable_to_download_files": "Nepavyksta atsisiųsti failų",
"unable_to_edit_exclusion_pattern": "Nepavyksta redaguoti išimčių šablono",
"unable_to_edit_import_path": "Nepavyksta redaguoti išimčių kelio",
"unable_to_empty_trash": "Nepavyko ištrinti šiukšliadėžės",
"unable_to_enter_fullscreen": "Nepavyksta pereiti į viso ekrano režimą",
"unable_to_exit_fullscreen": "Nepavyksta išeiti iš viso ekrano režimo",
"unable_to_get_comments_number": "Nepavyko gauti komentarų skaičiaus",
"unable_to_get_shared_link": "Nepavyko gauti bendrinimo nuorodos",
"unable_to_hide_person": "Nepavyksta paslėpti žmogaus",
"unable_to_link_motion_video": "Nepavyko susieti judesio video",
"unable_to_link_oauth_account": "Nepavyko susieti su OAuth paskyra",
"unable_to_log_out_all_devices": "Nepavyksta atjungti visų įrenginių",
"unable_to_log_out_device": "Nepavyksta atjungti įrenginio",
"unable_to_login_with_oauth": "Nepavyko prisijungti su OAuth",
"unable_to_play_video": "Nepavyksta paleisti vaizdo įrašo",
"unable_to_reassign_assets_existing_person": "Nepavyko priskirti elementų {name, select, null {egzistuojančiam asmeniui} other {{name}}}",
"unable_to_reassign_assets_new_person": "Nepavyko priskirti elementų naujam asmeniui",
"unable_to_refresh_user": "Nepavyksta atnaujinti naudotojo",
"unable_to_remove_album_users": "Nepavyko pašalinti naudotojų iš albumo",
"unable_to_remove_api_key": "Nepavyko pašalinti API rakto",
"unable_to_remove_assets_from_shared_link": "Nepavyko iš bendrinimo nuorodos pašalinti elementų",
"unable_to_remove_library": "Nepavyksta pašalinti bibliotekos",
"unable_to_remove_partner": "Nepavyksta pašalinti partnerio",
"unable_to_remove_reaction": "Nepavyksta pašalinti reakcijos",
"unable_to_reset_password": "Nepavyko atnaujinti slaptažodžio",
"unable_to_reset_pin_code": "Nepavyko atnaujinti PIN kodo",
"unable_to_resolve_duplicate": "Nepavyko sutvarkyti dublikatų",
"unable_to_restore_assets": "Nepavyko atstatyti elementų",
"unable_to_restore_trash": "Nepavyko atstatyti iš šiukšliadėžės",
"unable_to_restore_user": "Nepavyko atstatyti naudotojo",
"unable_to_save_album": "Nepavyko išsaugoti albumo",
"unable_to_save_api_key": "Nepavyko išsaugoti API rakto",
"unable_to_save_date_of_birth": "Nepavyko išsaugoti gimimo datos",
"unable_to_save_name": "Nepavyko išsaugoti vardo",
"unable_to_save_profile": "Nepavyko išsaugoti profilio",
"unable_to_save_settings": "Nepavyksta išsaugoti nustatymų",
"unable_to_scan_libraries": "Nepavyksta nuskaityti bibliotekų",
@@ -622,39 +1001,104 @@
"unable_to_set_profile_picture": "Nepavyksta nustatyti profilio nuotraukos",
"unable_to_submit_job": "Napvyko sukurti užduoties",
"unable_to_trash_asset": "Nepavyko perkelti į šiukšliadėžę",
"unable_to_unlink_account": "Nepavyko atsieti paskyrų",
"unable_to_unlink_motion_video": "Nepavyko atsieti judesio video",
"unable_to_update_album_cover": "Nepavyko atnaujinti albumo viršelio",
"unable_to_update_album_info": "Nepavyko atnaujinti albumo informacijos",
"unable_to_update_library": "Nepavyko atnaujinti bibliotekos",
"unable_to_update_location": "Nepavyko atnaujinti vietovės",
"unable_to_update_settings": "Nepavyko atnaujinti nustatymų",
"unable_to_update_timeline_display_status": "Nepavyko atnaujinti laiko juostos rodymo statuso",
"unable_to_update_user": "Nepavyko atnaujinti naudotoją",
"unable_to_upload_file": "Nepavyksta įkelti failo"
},
"exif": "Exif",
"exif_bottom_sheet_description": "Pridėti aprašymą...",
"exif_bottom_sheet_description_error": "Klaida atnaujinant aprašymą",
"exif_bottom_sheet_details": "DETALĖS",
"exif_bottom_sheet_location": "VIETOVĖ",
"exif_bottom_sheet_people": "ŽMONĖS",
"exif_bottom_sheet_person_add_person": "Pridėti vardą",
"exit_slideshow": "Išeiti iš skaidrių peržiūros",
"expand_all": "Išskleisti viską",
"experimental_settings_new_asset_list_subtitle": "Dirbama",
"experimental_settings_new_asset_list_title": "Įgalinti eksperimentinį nuotraukų tinklelį",
"experimental_settings_subtitle": "Naudokite savo pačių rizika!",
"experimental_settings_title": "Eksperimentinis",
"expire_after": "Galiojimas baigiasi",
"expired": "Nebegalioja",
"expires_date": "Nebegalios už {date}",
"explore": "Naršyti",
"explorer": "Naršyklė",
"export": "Eksportuoti",
"export_as_json": "Eksportuoti kaip JSON",
"export_database": "Eksportuoti duomenų bazę",
"export_database_description": "Eksportuoti SQLite duomenų bazę",
"extension": "Plėtinys",
"external": "Išorinis",
"external_libraries": "Išorinės bibliotekos",
"external_network_sheet_info": "When not on the preferred WiFi network, the app will connect to the server through the first of the below URLs it can reach, starting from top to bottom",
"external_network": "Išorinis tinklas",
"external_network_sheet_info": "Kai neprisijungta prie pageidaujamo Wi-Fi tinklo, programa jungsis prie serverio per pirmą URL nuorodą, kurią galės pasiekti, pradedant nuo viršaus į apačią",
"face_unassigned": "Nepriskirta",
"failed": "Įvyko klaida",
"failed_to_authenticate": "Nepavyko autentifikuoti",
"failed_to_load_assets": "Nepavyko įkelti elementų",
"failed_to_load_folder": "Nepavyko įkelti katalogą",
"favorite": "Mėgstamiausias",
"favorite_action_prompt": "{count} pridėta prie mėgstamiausių",
"favorite_or_unfavorite_photo": "Įtraukti prie arba pašalinti iš mėgstamiausių",
"favorites": "Mėgstamiausi",
"favorites_page_no_favorites": "Nerasta mėgstamiausių elementų",
"feature_photo_updated": "Pageidaujama nuotrauka atnaujinta",
"features": "Funkcijos",
"features_setting_description": "Valdyti aplikacijos funkcijas",
"file_name": "Failo pavadinimas",
"file_name_or_extension": "Failo pavadinimas arba plėtinys",
"filename": "Failopavadinimas",
"filetype": "Failo tipas",
"filter": "Filtras",
"filter_people": "Filtruoti žmones",
"filter_places": "Filtruoti vietoves",
"find_them_fast": "Raskite greitai paieškoje pagal vardą",
"first": "Pirmas",
"fix_incorrect_match": "Pataisyti neteisingą porą",
"folder": "Katalogas",
"folder_not_found": "Katalogas nerastas",
"folders": "Aplankai",
"folders_feature_description": "Peržiūrėkite failų sistemoje esančias nuotraukas ir vaizdo įrašus aplankų rodinyje",
"forgot_pin_code_question": "Pamiršote savo PIN?",
"forward": "Pirmyn",
"gcast_enabled": "Google Cast",
"gcast_enabled_description": "Kad veiktų, ši funkcija įkelia išorinius „Google“ išteklius.",
"general": "Bendri",
"geolocation_instruction_location": "Paspauskite ant elemento su GPS koordinatėmis norint naudoti tą vietovę arba pasirinkite vietovę tiesiogiai žemėlapyje",
"get_help": "Gauti pagalbos",
"get_wifiname_error": "Nepavyko gauti Wi-Fi pavadinimo. Įsitikinkite, kad suteikti būtini leidimai ir esate prisijungę prie Wi-Fi tinklo",
"getting_started": "Pradedama",
"go_back": "Eiti atgal",
"go_to_folder": "Eiti į katalogą",
"go_to_search": "Eiti į paiešką",
"gps": "GPS",
"gps_missing": "Be GPS",
"grant_permission": "Suteikti leidimą",
"group_albums_by": "Grupuoti albumus pagal...",
"group_country": "Grupuoti pagal šalis",
"group_no": "Negrupuoti",
"group_owner": "Grupuoti pagal savininką",
"group_places_by": "Grupuoti vietoves pagal...",
"group_year": "Grupuoti pagal metus",
"haptic_feedback_switch": "Įjungti haptinį grįžtamąjį ryšį",
"haptic_feedback_title": "Haptinis grįžtamasis ryšys",
"has_quota": "Turi kvotą",
"hash_asset": "Maišymo elementas",
"hashed_assets": "Sumaišyti elementai",
"hashing": "Maišoma",
"header_settings_add_header_tip": "Pridėti antraštę",
"header_settings_field_validator_msg": "Reikšmė negali būti tuščia",
"header_settings_header_name_input": "Antraštės pavadinimas",
"header_settings_header_value_input": "Antraštės reikšmė",
"headers_settings_tile_subtitle": "Apibrėžkite tarpinio serverio antraštes, kurias programa turėtų siųsti su kiekviena tinklo užklausa",
"headers_settings_tile_title": "Pasirinktinės tarpinio serverio antraštės",
"hi_user": "Labas {name} ({email})",
"hide_all_people": "Slėpti visus asmenis",
"hide_gallery": "Slėpti galeriją",
@@ -662,7 +1106,17 @@
"hide_password": "Slėpti slaptažodį",
"hide_person": "Slėpti asmenį",
"hide_unnamed_people": "Slėpti neįvardintus asmenis",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_add_to_album_conflicts": "Pridėta {added} elementų į albumą {album}. {failed} elementai jau yra albume.",
"home_page_add_to_album_err_local": "Kol kas negalima pridėti vietinių elementų į albumus, praleidžiama",
"home_page_add_to_album_success": "Pridėta {added} elementų į albumą {album}.",
"home_page_album_err_partner": "Kol kas negalima pridėti partnerio elementų į albumą, praleidžiama",
"home_page_archive_err_local": "Kol kas negalima archyvuoti vietinių elementų, praleidžiama",
"home_page_archive_err_partner": "Negalima archyvuoti partnerio elementų, praleidžiama",
"home_page_building_timeline": "Kuriama laiko juosta",
"home_page_delete_err_partner": "Negalima ištrinti partnerio elementų, praleidžiama",
"home_page_delete_remote_err_local": "Vietiniai elementai ištrinant nuotolinį pasirinkimą, praleidžiami",
"home_page_favorite_err_local": "Kol kad negalima priskirti mėgstamiausių vietinių elementų, praleidžiama",
"home_page_first_time_notice": "Jei jūs naudojate programą pirmą kartą, tai prašome pasirinkti atsarginės kopijos albumą, kad laiko juosta galėtų tvarkyti albumo nuotraukas ir vaizdo įrašus",
"home_page_locked_error_local": "Nepavyko perkelti lokalių failų į užrakintą aplanką, praleidžiama",
"home_page_locked_error_partner": "Nepavyko perkelti partnerio failų į užrakintą aplanką, praleidžiama",
"hour": "Valanda",
@@ -707,7 +1161,7 @@
"list": "Sąrašas",
"loading": "Kraunama",
"loading_search_results_failed": "Nepavyko užkrauti paieškos rezultatų",
"location_permission_content": "In order to use the auto-switching feature, Immich needs precise location permission so it can read the current WiFi network's name",
"location_permission_content": "Norint naudoti automatinio persijungimo opciją, Immich reikia tikslios vietovės leidimo, kad galėtų nuskaityti Wi-Fi tinklo pavadinimą",
"locked_folder": "Užrakintas aplankas",
"log_out": "Atsijungti",
"log_out_all_devices": "Atsijungti iš visų įrenginių",
@@ -727,7 +1181,10 @@
"manage_your_devices": "Valdyti prijungtus įrenginius",
"manage_your_oauth_connection": "Tvarkyti OAuth prisijungimą",
"map": "Žemėlapis",
"map_assets_in_bounds": "{count, plural, =0 {Nuotraukų nėra} one {# nuotrauka} other {# nuotraukos}}",
"map_settings": "Žemėlapio nustatymai",
"map_settings_date_range_option_days": "Pastarąsias {days} dienas",
"map_settings_date_range_option_years": "Pastaruosius {years} metus",
"map_settings_include_show_archived": "Įtraukti archyvuotus",
"matches": "Atitikmenys",
"media_type": "Laikmenos tipas",
@@ -785,6 +1242,7 @@
"notification_toggle_setting_description": "Įjungti el. pašto pranešimus",
"notifications": "Pranešimai",
"notifications_setting_description": "Tvarkyti pranešimus",
"oauth": "OAuth",
"official_immich_resources": "Oficialūs Immich ištekliai",
"offline": "Neprisijungęs",
"oldest_first": "Seniausias pirmas",
@@ -805,6 +1263,7 @@
"partner_can_access": "{partner} gali naudotis",
"partner_can_access_assets": "Visos jūsų nuotraukos ir vaizdo įrašai, išskyrus archyvuotus ir ištrintus",
"partner_can_access_location": "Vieta, kurioje darytos nuotraukos",
"partner_page_stop_sharing_content": "{partner} daugiau nebegalės pasiekti jūsų nuotraukų.",
"partners": "Partneriai",
"password": "Slaptažodis",
"password_does_not_match": "Slaptažodis nesutampa",
@@ -859,7 +1318,7 @@
"purchase_lifetime_description": "Pirkimas visam gyvenimui",
"purchase_option_title": "PIRKIMO PASIRINKIMAS",
"purchase_panel_info_1": "„Immich“ kūrimas užima daug laiko ir pastangų, o visą darbo dieną dirba inžinieriai, kad jis būtų kuo geresnis. Mūsų misija yra, kad atvirojo kodo programinė įranga ir etiška verslo praktika taptų tvariu kūrėjų pajamų šaltiniu ir sukurtų privatumą gerbiančią ekosistemą su realiomis alternatyvomis išnaudojamoms debesijos paslaugoms.",
"purchase_panel_info_2": "Kadangi esame įsipareigoję nepridėti mokamų sienų, šis pirkinys nesuteiks jums jokių papildomų Immich funkcijų. Mes tikime, kad tokie naudotojai kaip jūs palaikys nuolatinį Immich vystymąsi.",
"purchase_panel_info_2": "Kadangi esame įsipareigoję nepridėti mokamų sienų, šis pirkinys nesuteiks jums jokių papildomų Immich funkcijų. Mes tikime, kad tokie naudotojai kaip jūs palaikys nuolatinį Immich vystymąsi.",
"purchase_panel_title": "Palaikykite projektą",
"purchase_per_server": "Vienam serveriui",
"purchase_per_user": "Vienam naudotojui",
@@ -998,7 +1457,11 @@
"setting_image_viewer_preview_title": "Užkrauti peržiūros nuotrauką",
"setting_image_viewer_title": "Nuotraukos",
"setting_languages_apply": "Pritaikyti",
"setting_notifications_notify_failures_grace_period": "Informuoti apie foninio atsarginio kopijavimo nesėkmes: {duration}",
"setting_notifications_notify_hours": "{count} valandų",
"setting_notifications_notify_minutes": "{count} minučių",
"setting_notifications_notify_never": "niekada",
"setting_notifications_notify_seconds": "{count} sekundžių",
"setting_notifications_single_progress_subtitle": "Detali įkėlimo progreso informacija kiekvienam elementui",
"settings": "Nustatymai",
"settings_require_restart": "Prašome perkrauti Immich, siekiant pritaikyti šį nustatymą",
@@ -1006,13 +1469,29 @@
"setup_pin_code": "Nustatyti PIN kodą",
"share": "Dalintis",
"share_add_photos": "Įtraukti nuotraukų",
"share_assets_selected": "{count} pažymėta",
"share_dialog_preparing": "Ruošiama...",
"share_link": "Bendrinti nuorodą",
"shared": "Bendrinami",
"shared_by_user": "Bendrina {user}",
"shared_by_you": "Bendrinama jūsų",
"shared_from_partner": "Nuotraukos iš {partner}",
"shared_intent_upload_button_progress_text": "{current} / {total} Įkelta",
"shared_link_clipboard_copied_massage": "Nukopijuota į iškarpinę",
"shared_link_clipboard_text": "Nuoroda: {link}\nSlaptažodis: {password}",
"shared_link_edit_expire_after_option_days": "{count} dienų",
"shared_link_edit_expire_after_option_hours": "{count} valandų",
"shared_link_edit_expire_after_option_minutes": "{count} minučių",
"shared_link_edit_expire_after_option_months": "{count} mėnesių",
"shared_link_edit_expire_after_option_year": "{count} metų",
"shared_link_expires_day": "Galiojimas baigsis už {count} dienos",
"shared_link_expires_days": "Galiojimas baigsis už {count} dienų",
"shared_link_expires_hour": "Galiojimas baigsis už {count} valandos",
"shared_link_expires_hours": "Galiojimas baigsis už {count} valandų",
"shared_link_expires_minute": "Galiojimas baigsis už {count} minutės",
"shared_link_expires_minutes": "Galiojimas baigsis už {count} minučių",
"shared_link_expires_second": "Galiojimas baigsis už {count} sekundės",
"shared_link_expires_seconds": "Galiojimas baigsis už {count} sekundžių",
"shared_link_options": "Bendrinimo nuorodos parametrai",
"shared_links": "Bendrinimo nuorodos",
"shared_photos_and_videos_count": "{assetCount, plural, one {# bendrinama nuotrauka ir vaizdo įrašas} few {# bendrinamos nuotraukos ir vaizdo įrašai} other {# bendrinamų nuotraukų ir vaizdo įrašų}}",
@@ -1092,6 +1571,7 @@
"template": "Šablonas",
"theme": "Tema",
"theme_selection": "Temos pasirinkimas",
"theme_setting_asset_list_tiles_per_row_title": "Elementų per eilutę ({count})",
"theme_setting_primary_color_title": "Pagrindinė spalva",
"theme_setting_system_primary_color_title": "Naudoti sistemos spalvą",
"theme_setting_system_theme_switch": "Automatinė (Naudoti sistemos nustatymus)",
@@ -1110,8 +1590,10 @@
"trash_no_results_message": "Į šiukšliadėžę perkeltos nuotraukos ir vaizdo įrašai bus rodomi čia.",
"trash_page_delete_all": "Ištrinti Visus",
"trash_page_empty_trash_dialog_content": "Ar norite ištrinti išmestus elementus? Šie elementai bus visam laikui pašalinti iš Immich",
"trash_page_info": "Šiukšliadėžės elementai bus galutinai ištrinti už {days} dienų",
"trash_page_no_assets": "Nėra išmestų elementų",
"trash_page_restore_all": "Atkurti Visus",
"trash_page_title": "Šiukšlių ({count})",
"trashed_items_will_be_permanently_deleted_after": "Į šiukšliadėžę perkelti elementai bus visam laikui ištrinti po {days, plural, one {# dienos} other {# dienų}}.",
"type": "Tipas",
"unarchive": "Išarchyvuoti",
@@ -1146,7 +1628,8 @@
"upload_success": "Įkėlimas pavyko, norėdami pamatyti naujai įkeltus elementus perkraukite puslapį.",
"upload_to_immich": "Įkelti į Immich ({count})",
"uploading": "Įkeliama",
"usage": "Naudojymas",
"url": "URL",
"usage": "Naudojimas",
"use_biometric": "Naudoti biometriją",
"use_current_connection": "naudoti dabartinį ryšį",
"user": "Naudotojas",

View File

@@ -23,7 +23,7 @@
"add_partner": "Pievienot partneri",
"add_path": "Pievienot ceļu",
"add_photos": "Pievienot fotoattēlus",
"add_tag": "Pievienot Atzīmi",
"add_tag": "Pievienot atzīmi",
"add_to": "Pievienot…",
"add_to_album": "Pievienot albumam",
"add_to_album_bottom_sheet_added": "Pievienots {album}",
@@ -45,13 +45,14 @@
"authentication_settings_disable_all": "Vai tiešām vēlaties atspējot visas pieteikšanās metodes? Pieteikšanās tiks pilnībā atspējota.",
"authentication_settings_reenable": "Lai atkārtoti iespējotu, izmantojiet <link>Servera Komandu</link>.",
"background_task_job": "Fona Uzdevumi",
"backup_database": "Izveidot datu bāzes izgāztuvi",
"backup_database_enable_description": "Iespējot datu bāzes izgāztuvi",
"backup_keep_last_amount": "Iepriekšējo izgāztuvju daudzums, kas jāsaglabā",
"backup_onboarding_1_description": "ārpussaites kopēšana mākonī vai citā fiziskā vietā.",
"backup_onboarding_2_description": "lokālas kopijas citās ierīcēs. Šis iekļauj galvenos failus kā arī dublētu kōpiju ar tiem failiem lokāli.",
"backup_database": "Izveidot datu bāzes izrakstu",
"backup_database_enable_description": "Iespējot datu bāzes izrakstus",
"backup_keep_last_amount": "Iepriekšējo izrakstu daudzums, kas jāsaglabā",
"backup_onboarding_1_description": "ārēja kopija mākonī vai citā fiziskā atrašanās vietā.",
"backup_onboarding_2_description": "vietējās kopijas citās ierīcēs. Tas ietver galvenos failus un šo failu vietējo rezerves kopiju.",
"backup_onboarding_title": "Rezerves kopijas",
"backup_settings_description": "Datubāzes dublēšanas iestatījumu pārvaldība",
"backup_settings": "Datubāzes izrakstu iestatījumi",
"backup_settings_description": "Datubāzes izrakstu iestatījumu pārvaldība",
"cleared_jobs": "Notīrīti uzdevumi priekš: {job}",
"config_set_by_file": "Konfigurāciju pašlaik iestata konfigurācijas fails",
"confirm_delete_library": "Vai tiešām vēlaties dzēst {library} bibliotēku?",
@@ -777,6 +778,7 @@
"let_others_respond": "Ļaut citiem atbildēt",
"level": "Līmenis",
"library": "Bibliotēka",
"library_options": "Bibliotēkas opcijas",
"library_page_device_albums": "Albumi ierīcē",
"library_page_new_album": "Jauns albums",
"library_page_sort_asset_count": "Failu skaits",
@@ -784,6 +786,8 @@
"library_page_sort_last_modified": "Pēdējās izmaiņas",
"library_page_sort_title": "Albuma virsraksts",
"licenses": "Licences",
"link_to_oauth": "Piesaistīt OAuth",
"linked_oauth_account": "Piesaistītais OAuth konts",
"list": "Saraksts",
"loading": "Ielādē",
"local_network": "Lokālais tīkls",
@@ -943,6 +947,8 @@
"open_the_search_filters": "Atvērt meklēšanas filtrus",
"options": "Iestatījumi",
"or": "vai",
"organize_into_albums": "Sakārtot albumos",
"organize_into_albums_description": "Ievietot esošās fotogrāfijas albumos, izmantojot pašreizējos sinhronizācijas iestatījumus",
"organize_your_library": "Bibliotēkas organizēšana",
"original": "oriģināls",
"other": "Citi",
@@ -1297,6 +1303,8 @@
"support": "Atbalsts",
"support_and_feedback": "Atbalsts un atsauksmes",
"sync": "Sinhronizēt",
"sync_status": "Sinhronizācijas statuss",
"sync_status_subtitle": "Skatīt un pārvaldīt sinhronizācijas sistēmu",
"theme": "Dizains",
"theme_setting_asset_list_storage_indicator_title": "Rādīt krātuves indikatoru uz aktīvu elementiem",
"theme_setting_asset_list_tiles_per_row_title": "Failu skaits rindā ({count})",
@@ -1337,6 +1345,7 @@
"trash_page_select_assets_btn": "Atlasīt aktīvus",
"trash_page_title": "Atkritne ({count})",
"trashed_items_will_be_permanently_deleted_after": "Faili no atkritnes tiks neatgriezeniski dzēsti pēc {days, plural, one {# dienas} other {# dienām}}.",
"troubleshoot": "Problēmu novēršana",
"type": "Veids",
"unable_to_change_pin_code": "Neizdevās nomainīt PIN kodu",
"unable_to_setup_pin_code": "Neizdevās uzstādīt PIN kodu",

View File

@@ -1056,6 +1056,706 @@
"group_no": "गटबद्ध नाही",
"group_owner": "मालकानुसार गट करा",
"group_places_by": "स्थळे गटबद्ध करा: …",
"notification_permission_dialog_content": "सूचना सक्षम करण्यासाठी सेटिंग्जमध्ये जा आणि अनुमती द्या.",
"notification_permission_list_tile_content": "सूचना सक्षम करण्यासाठी परवानगी द्या.",
"notification_permission_list_tile_enable_button": "सूचना सक्षम करा",
"notification_permission_list_tile_title": "सूचना परवानगी",
"notification_toggle_setting_description": "ईमेल सूचना सक्षम करा",
"notifications": "सूचना",
"notifications_setting_description": "सूचना व्यवस्थापित करा",
"oauth": "OAuth",
"official_immich_resources": "अधिकृत Immich संसाधने",
"offline": "ऑफलाइन",
"offset": "ऑफसेट",
"ok": "ठीक",
"oldest_first": "सर्वात जुने आधी",
"on_this_device": "या डिव्हाइसवर",
"onboarding": "ऑनबोर्डिंग",
"onboarding_locale_description": "तुमची पसंतीची भाषा निवडा. हे नंतर सेटिंग्जमध्ये बदलू शकता.",
"onboarding_privacy_description": "खालील (पर्यायी) वैशिष्ट्ये बाह्य सेवांवर अवलंबून आहेत आणि सेटिंग्जमध्ये कधीही अक्षम करता येतात.",
"onboarding_server_welcome_description": "काही सामान्य सेटिंग्जसह तुमची इन्स्टन्स सेटअप करूया.",
"onboarding_theme_description": "तुमच्या इन्स्टन्ससाठी रंग थीम निवडा. हे नंतर सेटिंग्जमध्ये बदलू शकता.",
"onboarding_user_welcome_description": "चला, सुरुवात करूया!",
"onboarding_welcome_user": "स्वागत आहे, {user}",
"online": "ऑनलाइन",
"only_favorites": "फक्त आवडते",
"open": "उघडा",
"open_in_map_view": "नकाशा दृश्यात उघडा",
"open_in_openstreetmap": "OpenStreetMap मध्ये उघडा",
"open_the_search_filters": "शोध फिल्टर उघडा",
"options": "पर्याय",
"or": "किंवा",
"organize_into_albums": "अल्बममध्ये आयोजित करा",
"organize_into_albums_description": "सध्याच्या समक्रमण सेटिंग्ज वापरून विद्यमान फोटो अल्बममध्ये ठेवा",
"organize_your_library": "तुमची लायब्ररी व्यवस्थित करा",
"original": "मूळ",
"other": "इतर",
"other_devices": "इतर उपकरणे",
"other_entities": "इतर घटक",
"other_variables": "इतर चल",
"owned": "मालकीचे",
"owner": "मालक",
"partner": "भागीदार",
"partner_can_access": "{partner} ला प्रवेश आहे",
"partner_can_access_assets": "संग्रहित व हटविलेले वगळता तुमचे सर्व फोटो आणि व्हिडिओ",
"partner_can_access_location": "ज्या ठिकाणी तुमचे फोटो काढले गेले ते स्थान",
"partner_list_user_photos": "{user} चे फोटो",
"partner_list_view_all": "सर्व पहा",
"partner_page_empty_message": "तुमचे फोटो अजून कोणत्याही भागीदारासोबत शेअर केलेले नाहीत.",
"partner_page_no_more_users": "जोडण्यासाठी आणखी वापरकर्ते नाहीत",
"partner_page_partner_add_failed": "भागीदार जोडण्यात अयशस्वी",
"partner_page_select_partner": "भागीदार निवडा",
"partner_page_shared_to_title": "यांना शेअर केले",
"partner_page_stop_sharing_content": "{partner} आता तुमचे फोटो पाहू शकणार नाही.",
"partner_sharing": "भागीदार शेअरिंग",
"partners": "भागीदार",
"password": "पासवर्ड",
"password_does_not_match": "पासवर्ड जुळत नाही",
"password_required": "पासवर्ड आवश्यक",
"password_reset_success": "पासवर्ड रीसेट यशस्वी",
"past_durations": {
"days": "मागील {days, plural, one {# दिवस} other {# दिवस}}",
"hours": "मागील {hours, plural, one {# तास} other {# तास}}",
"years": "मागील {years, plural, one {# वर्ष} other {# वर्षे}}"
},
"path": "मार्ग",
"pattern": "नमुना",
"pause": "थांबवा",
"pause_memories": "आठवणी थांबवा",
"paused": "थांबवले",
"pending": "प्रलंबित",
"people": "लोक",
"people_edits_count": "संपादित {count, plural, one {# व्यक्ती} other {# लोक}}",
"people_feature_description": "लोकांनुसार गटबद्ध फोटो आणि व्हिडिओ ब्राउझ करा",
"people_sidebar_description": "साइडबारमध्ये “लोक” साठी दुवा दाखवा",
"permanent_deletion_warning": "कायमस्वरूपी विलोपन सूचना",
"permanent_deletion_warning_setting_description": "अ‍ॅसेट्स कायमचे हटवताना सूचना दाखवा",
"permanently_delete": "कायमचे हटवा",
"permanently_delete_assets_count": "{count, plural, one {अ‍ॅसेट} other {अ‍ॅसेट्स}} कायमचे हटवा",
"permanently_delete_assets_prompt": "आपण {count, plural, one {हा अ‍ॅसेट कायमचा हटवू इच्छिता?} other {हे <b></b> अ‍ॅसेट्स कायमचे हटवू इच्छिता?}} यामुळे {count, plural, one {तो त्याच्या} other {ते त्यांच्या}} अल्बम(मधून) देखील काढले जातील.",
"permanently_deleted_asset": "कायमचा हटवलेला अ‍ॅसेट",
"permanently_deleted_assets_count": "कायमचे हटवले {count, plural, one {# अ‍ॅसेट} other {# अ‍ॅसेट्स}}",
"permission": "परवानगी",
"permission_empty": "तुमची परवानगी रिक्त असू नये",
"permission_onboarding_back": "मागे",
"permission_onboarding_continue_anyway": "तरीही पुढे जा",
"permission_onboarding_get_started": "सुरू करा",
"permission_onboarding_go_to_settings": "सेटिंग्जमध्ये जा",
"permission_onboarding_permission_denied": "परवानगी नाकारली. Immich वापरण्यासाठी, सेटिंग्जमध्ये फोटो आणि व्हिडिओ परवानग्या द्या.",
"permission_onboarding_permission_granted": "परवानगी मंजूर! सर्व तयार.",
"permission_onboarding_permission_limited": "परवानगी मर्यादित. Immich ला संपूर्ण गॅलरी संग्रहाचा बॅकअप व व्यवस्थापन करण्यासाठी, सेटिंग्जमध्ये फोटो आणि व्हिडिओ परवानग्या द्या.",
"permission_onboarding_request": "तुमचे फोटो आणि व्हिडिओ पाहण्यासाठी Immich ला परवानगी आवश्यक आहे.",
"person": "व्यक्ती",
"person_age_months": "{months, plural, one {# महिना} other {# महिने}} वय",
"person_age_year_months": "1 वर्ष, {months, plural, one {# महिना} other {# महिने}} वय",
"person_age_years": "{years, plural, other {# वर्षांचे}}",
"person_birthdate": "जन्म {date} रोजी",
"person_hidden": "{name}{hidden, select, true { {hidden}} other {}}",
"photo_shared_all_users": "तुम्ही सर्व वापरकर्त्यांसोबत फोटो शेअर केले आहेत असे दिसते किंवा शेअर करण्यासाठी कोणताही वापरकर्ता नाही.",
"photos": "फोटो",
"photos_and_videos": "फोटो आणि व्हिडिओ",
"photos_count": "{count, plural, one {{count, number} फोटो} other {{count, number} फोटो}}",
"photos_from_previous_years": "मागील वर्षांतील फोटो",
"pick_a_location": "स्थान निवडा",
"pin_code_changed_successfully": "PIN कोड यशस्वीरित्या बदलला",
"pin_code_reset_successfully": "PIN कोड यशस्वीरित्या रीसेट केला",
"pin_code_setup_successfully": "PIN कोड यशस्वीरित्या सेट केला",
"pin_verification": "PIN कोड पडताळणी",
"place": "स्थान",
"places": "स्थाने",
"places_count": "{count, plural, one {{count, number} स्थान} other {{count, number} स्थाने}}",
"play": "प्ले करा",
"play_memories": "आठवणी प्ले करा",
"play_motion_photo": "मोशन फोटो प्ले करा",
"play_or_pause_video": "व्हिडिओ प्ले किंवा पॉज करा",
"please_auth_to_access": "प्रवेशासाठी कृपया प्रमाणीकरण करा",
"port": "पोर्ट",
"preferences_settings_subtitle": "अ‍ॅपची प्राधान्ये व्यवस्थापित करा",
"preferences_settings_title": "प्राधान्ये",
"preset": "प्रिसेट",
"preview": "पूर्वावलोकन",
"previous": "मागील",
"previous_memory": "मागील आठवण",
"previous_or_next_day": "दिवस पुढे/मागे",
"previous_or_next_month": "महिना पुढे/मागे",
"previous_or_next_photo": "फोटो पुढे/मागे",
"previous_or_next_year": "वर्ष पुढे/मागे",
"primary": "प्राथमिक",
"privacy": "गोपनीयता",
"profile": "प्रोफाइल",
"profile_drawer_app_logs": "लॉग्स",
"profile_drawer_client_out_of_date_major": "मोबाइल अ‍ॅप कालबाह्य आहे. कृपया नवीनतम मेजर आवृत्तीवर अद्यतन करा.",
"profile_drawer_client_out_of_date_minor": "मोबाइल अ‍ॅप कालबाह्य आहे. कृपया नवीनतम माइनर आवृत्तीवर अद्यतन करा.",
"profile_drawer_client_server_up_to_date": "क्लायंट आणि सर्व्हर अद्ययावत आहेत",
"profile_drawer_github": "गिटहब",
"profile_drawer_readonly_mode": "फक्त-वाचन मोड सक्षम. बाहेर पडण्यासाठी वापरकर्त्याच्या अवतार आयकॉनवर लांब-प्रेस करा.",
"profile_drawer_server_out_of_date_major": "सर्व्हर कालबाह्य आहे. कृपया नवीनतम मेजर आवृत्तीवर अद्यतन करा.",
"profile_drawer_server_out_of_date_minor": "सर्व्हर कालबाह्य आहे. कृपया नवीनतम माइनर आवृत्तीवर अद्यतन करा.",
"profile_image_of_user": "{user} ची प्रोफाइल प्रतिमा",
"profile_picture_set": "प्रोफाइल चित्र सेट केले.",
"public_album": "सार्वजनिक अल्बम",
"public_share": "सार्वजनिक शेअर",
"purchase_account_info": "समर्थक",
"purchase_activated_subtitle": "Immich आणि मुक्त-स्रोत सॉफ्टवेअरला पाठिंबा दिल्याबद्दल धन्यवाद",
"purchase_activated_time": "{date} रोजी सक्रिय केले",
"purchase_activated_title": "तुमची की यशस्वीपणे सक्रिय करण्यात आली आहे",
"purchase_button_activate": "सक्रिय करा",
"purchase_button_buy": "खरेदी करा",
"purchase_button_buy_immich": "Immich खरेदी करा",
"purchase_button_never_show_again": "पुन्हा दाखवू नका",
"purchase_button_reminder": "३० दिवसांनी मला आठवण करून द्या",
"purchase_button_remove_key": "की हटवा",
"purchase_button_select": "निवडा",
"purchase_failed_activation": "सक्रिय करण्यात अयशस्वी! योग्य प्रोडक्ट कीसाठी कृपया तुमचे ईमेल तपासा!",
"purchase_individual_description_1": "वैयक्तिक वापरासाठी",
"purchase_individual_description_2": "समर्थक स्थिती",
"purchase_individual_title": "वैयक्तिक",
"purchase_input_suggestion": "प्रॉडक्ट की आहे? खाली की टाका",
"purchase_license_subtitle": "सेवेच्या पुढील विकासासाठी Immich खरेदी करून साथ द्या",
"purchase_lifetime_description": "आयुष्यभराची खरेदी",
"purchase_option_title": "खरेदी पर्याय",
"purchase_panel_info_1": "Immich तयार करणे वेळखाऊ आणि कष्टाचे आहे. आमचे ध्येय मुक्त-स्रोत सॉफ्टवेअर व नैतिक व्यावसायिक पद्धतींमधून टिकाऊ उत्पन्न मिळवणे, विकसकांना आधार देणे आणि शोषणकारी क्लाउड सेवांना पर्याय देणारे गोपनीयतेचा मान राखणारे इकोसिस्टम तयार करणे हे आहे.",
"purchase_panel_info_2": "आम्ही पेवॉल न वाढवण्यास कटिबद्ध आहोत; त्यामुळे या खरेदीमुळे Immich मध्ये कोणतीही अतिरिक्त वैशिष्ट्ये उघडणार नाहीत. चालू विकासासाठी आम्ही तुमच्यासारख्या वापरकर्त्यांच्या पाठबळावर अवलंबून आहोत.",
"purchase_panel_title": "प्रकल्पाला साथ द्या",
"purchase_per_server": "प्रति सर्व्हर",
"purchase_per_user": "प्रति वापरकर्ता",
"purchase_remove_product_key": "प्रॉडक्ट की काढा",
"purchase_remove_product_key_prompt": "तुम्हाला नक्की प्रॉडक्ट की काढायची आहे का?",
"purchase_remove_server_product_key": "सर्व्हरची प्रॉडक्ट की काढा",
"purchase_remove_server_product_key_prompt": "तुम्हाला नक्की सर्व्हरची प्रॉडक्ट की काढायची आहे का?",
"purchase_server_description_1": "संपूर्ण सर्व्हरसाठी",
"purchase_server_description_2": "समर्थक स्थिती",
"purchase_server_title": "सर्व्हर",
"purchase_settings_server_activated": "सर्व्हरची प्रॉडक्ट की प्रशासकाद्वारे व्यवस्थापित केली जाते",
"query_asset_id": "अॅसेट ID चौकशी",
"queue_status": "रांगेत {count}/{total}",
"rating": "स्टार रेटिंग",
"rating_clear": "रेटिंग साफ करा",
"rating_count": "{count, plural, one {# तारा} other {# तारे}}",
"rating_description": "माहिती पॅनेलमध्ये EXIF रेटिंग दर्शवा",
"reaction_options": "रिऍक्शन पर्याय",
"read_changelog": "चेंजलॉग वाचा",
"readonly_mode_disabled": "फक्त-वाचन मोड निष्क्रिय केला",
"readonly_mode_enabled": "फक्त-वाचन मोड सक्षम केला",
"reassign": "पुन्हा नियुक्त करा",
"reassigned_assets_to_existing_person": "{count, plural, one {# आयटम} other {# आयटम}} {name, select, null {विद्यमान व्यक्तीकडे} other {{name} कडे}} पुन्हा नियुक्त केले",
"reassigned_assets_to_new_person": "{count, plural, one {# आयटम} other {# आयटम}} नव्या व्यक्तीकडे पुन्हा नियुक्त केले",
"reassing_hint": "निवडलेले आयटम विद्यमान व्यक्तीकडे नियुक्त करा",
"recent": "अलीकडील",
"recent-albums": "अलीकडील अल्बम",
"recent_searches": "अलीकडील शोध",
"recently_added": "नुकतेच जोडलेले",
"recently_added_page_title": "नुकतेच जोडलेले",
"recently_taken": "अलीकडे घेतलेले",
"recently_taken_page_title": "अलीकडे घेतलेले",
"refresh": "रीफ्रेश करा",
"refresh_encoded_videos": "एन्कोड केलेले व्हिडिओ रीफ्रेश करा",
"refresh_faces": "चेहरे रीफ्रेश करा",
"refresh_metadata": "मेटाडेटा रीफ्रेश करा",
"refresh_thumbnails": "थंबनेल रीफ्रेश करा",
"refreshed": "रीफ्रेश झाले",
"refreshes_every_file": "विद्यमान व नवीन सर्व फाइल्स पुन्हा वाचा",
"refreshing_encoded_video": "एन्कोड केलेला व्हिडिओ रीफ्रेश करत आहे",
"refreshing_faces": "चेहरे रीफ्रेश करत आहे",
"refreshing_metadata": "मेटाडेटा रीफ्रेश करत आहे",
"regenerating_thumbnails": "थंबनेल्स पुन्हा तयार करत आहे",
"remote": "दूरस्थ",
"remote_assets": "दूरस्थ आयटम",
"remove": "काढा",
"remove_assets_album_confirmation": "अल्बममधून {count, plural, one {# आयटम} other {# आयटम}} काढायचे आहेत का?",
"remove_assets_shared_link_confirmation": "या शेअर्ड दुव्यातून {count, plural, one {# आयटम} other {# आयटम}} काढायचे आहेत का?",
"remove_assets_title": "आयटम काढायचे?",
"remove_custom_date_range": "सानुकूल दिनांक श्रेणी काढा",
"remove_deleted_assets": "हटवलेले आयटम काढा",
"remove_from_album": "अल्बममधून काढा",
"remove_from_album_action_prompt": "अल्बममधून {count} काढले",
"remove_from_favorites": "आवडीतून काढा",
"remove_from_lock_folder_action_prompt": "लॉक केलेल्या फोल्डरमधून {count} काढले",
"remove_from_locked_folder": "लॉक फोल्डरमधून काढा",
"remove_from_locked_folder_confirmation": "हे फोटो आणि व्हिडिओ लॉक फोल्डरमधून बाहेर हलवायचे आहेत का? ते तुमच्या लायब्ररीमध्ये दिसतील.",
"remove_from_shared_link": "शेअर्ड दुव्यातून काढा",
"remove_memory": "मेमरी काढा",
"remove_photo_from_memory": "या मेमरीतून फोटो काढा",
"remove_tag": "टॅग काढा",
"remove_url": "URL काढा",
"remove_user": "वापरकर्ता काढा",
"removed_api_key": "काढलेली API की: {name}",
"removed_from_archive": "आर्काइव्हमधून काढले",
"removed_from_favorites": "आवडीतून काढले",
"removed_from_favorites_count": "{count, plural, other {आवडीतून # काढले}}",
"removed_memory": "मेमरी काढली",
"removed_photo_from_memory": "मेमरीतून फोटो काढला",
"removed_tagged_assets": "{count, plural, one {# आयटमवरून टॅग काढला} other {# आयटमवरून टॅग काढले}}",
"rename": "नाव बदला",
"repair": "दुरुस्ती",
"repair_no_results_message": "अनट्रॅक्ड व हरवलेल्या फाइल्स येथे दिसतील",
"replace_with_upload": "अपलोडने बदला",
"repository": "रिपॉझिटरी",
"require_password": "पासवर्ड आवश्यक",
"require_user_to_change_password_on_first_login": "पहिल्या लॉगिनवेळी वापरकर्त्याने पासवर्ड बदलणे आवश्यक",
"rescan": "पुन्हा स्कॅन करा",
"reset": "रीसेट करा",
"reset_password": "पासवर्ड रीसेट करा",
"reset_people_visibility": "लोकांची दृश्यता रीसेट करा",
"reset_pin_code": "PIN कोड रीसेट करा",
"reset_pin_code_description": "तुमचा PIN विसरला असल्यास, तो रीसेट करण्यासाठी सर्व्हर प्रशासकाशी संपर्क साधा",
"reset_pin_code_success": "PIN कोड यशस्वीरीत्या रीसेट केला",
"reset_pin_code_with_password": "पासवर्डने तुम्ही नेहमी PIN कोड रीसेट करू शकता",
"reset_sqlite": "SQLite डेटाबेस रीसेट करा",
"reset_sqlite_confirmation": "तुम्हाला नक्की SQLite डेटाबेस रीसेट करायचा आहे का? डेटा पुन्हा समक्रमित करण्यासाठी तुम्हाला लॉगआउट करून पुन्हा लॉगइन करावे लागेल",
"reset_sqlite_success": "SQLite डेटाबेस यशस्वीरीत्या रीसेट केला",
"reset_to_default": "डीफॉल्टवर रीसेट करा",
"resolve_duplicates": "डुप्लिकेट्स सोडवा",
"resolved_all_duplicates": "सर्व डुप्लिकेट्स सोडवले",
"restore": "पुनर्संचयित करा",
"restore_all": "सर्व पुनर्संचयित करा",
"restore_trash_action_prompt": "कचरापेटीतून {count} पुनर्संचयित केले",
"restore_user": "वापरकर्ता पुनर्संचयित करा",
"restored_asset": "पुनर्संचयित आयटम",
"resume": "पुन्हा सुरू करा",
"resume_paused_jobs": "{count, plural, one {# थांबवलेले काम} other {# थांबवलेली कामे}} पुन्हा सुरू करा",
"retry_upload": "अपलोड पुन्हा करा",
"review_duplicates": "डुप्लिकेट्सचे पुनरावलोकन करा",
"review_large_files": "मोठ्या फाइल्सचे पुनरावलोकन करा",
"role": "भूमिका",
"role_editor": "संपादक",
"role_viewer": "दर्शक",
"running": "चालू",
"save": "जतन करा",
"save_to_gallery": "गॅलरीमध्ये जतन करा",
"saved_api_key": "जतन केलेली API की",
"saved_profile": "जतन केलेले प्रोफाइल",
"saved_settings": "जतन केलेल्या सेटिंग्ज",
"say_something": "काहीतरी बोला",
"scaffold_body_error_occurred": "त्रुटी आली",
"scan_all_libraries": "सर्व लायब्ररी स्कॅन करा",
"scan_library": "स्कॅन करा",
"scan_settings": "स्कॅन सेटिंग्ज",
"scanning_for_album": "अल्बमसाठी स्कॅन करत आहे...",
"search": "शोधा",
"search_albums": "अल्बम शोधा",
"search_by_context": "परिस्थितीनुसार शोधा",
"search_by_description": "वर्णनानुसार शोधा",
"search_by_description_example": "सापा मधील हायकिंगचा दिवस",
"search_by_filename": "फाइल नाव/एक्स्टेंशननुसार शोधा",
"search_by_filename_example": "उदा. IMG_1234.JPG किंवा PNG",
"search_camera_make": "कॅमेरा निर्माता शोधा...",
"search_camera_model": "कॅमेरा मॉडेल शोधा...",
"search_city": "शहर शोधा...",
"search_country": "देश शोधा...",
"search_filter_apply": "फिल्टर लागू करा",
"search_filter_camera_title": "कॅमेरा प्रकार निवडा",
"search_filter_date": "तारीख",
"search_filter_date_interval": "{start} ते {end}",
"search_filter_date_title": "दिनांक श्रेणी निवडा",
"search_filter_display_option_not_in_album": "अल्बममध्ये नाही",
"search_filter_display_options": "प्रदर्शन पर्याय",
"search_filter_filename": "फाइल नावाने शोधा",
"search_filter_location": "स्थान",
"search_filter_location_title": "स्थान निवडा",
"search_filter_media_type": "माध्यम प्रकार",
"search_filter_media_type_title": "माध्यम प्रकार निवडा",
"search_filter_people_title": "लोक निवडा",
"search_for": "यासाठी शोधा",
"search_for_existing_person": "विद्यमान व्यक्ती शोधा",
"search_no_more_result": "आणखी परिणाम नाहीत",
"search_no_people": "कोणतीही व्यक्ती नाही",
"search_no_people_named": "“{name}” नावाची व्यक्ती सापडली नाही",
"search_no_result": "काहीही सापडले नाही; वेगळा शोध शब्द किंवा संयोजन वापरा",
"search_options": "शोध पर्याय",
"search_page_categories": "श्रेण्या",
"search_page_motion_photos": "मोशन फोटो",
"search_page_no_objects": "वस्तूंची माहिती उपलब्ध नाही",
"search_page_no_places": "ठिकाणांची माहिती उपलब्ध नाही",
"search_page_screenshots": "स्क्रीनशॉट्स",
"search_page_search_photos_videos": "तुमचे फोटो व व्हिडिओ शोधा",
"search_page_selfies": "सेल्फीज",
"search_page_things": "वस्तू",
"search_page_view_all_button": "सर्व पहा",
"search_page_your_activity": "तुमचे क्रियाकलाप",
"search_page_your_map": "तुमचा नकाशा",
"search_people": "लोक शोधा",
"search_places": "ठिकाणे शोधा",
"search_rating": "रेटिंगनुसार शोधा...",
"search_result_page_new_search_hint": "नवीन शोध",
"search_settings": "शोध सेटिंग्ज",
"search_state": "राज्य/स्टेट शोधा...",
"search_suggestion_list_smart_search_hint_1": "डीफॉल्टने स्मार्ट सर्च सुरू आहे; मेटाडेटा शोधण्यासाठी ही रचना वापरा. ",
"search_suggestion_list_smart_search_hint_2": "m:तुमचा-शोध-शब्द",
"search_tags": "टॅग्स शोधा...",
"search_timezone": "वेळक्षेत्र शोधा...",
"search_type": "शोध प्रकार",
"search_your_photos": "तुमचे फोटो शोधा",
"searching_locales": "लोकल्स शोधत आहे...",
"second": "सेकंद",
"see_all_people": "सर्व लोक पाहा",
"select": "निवडा",
"select_album_cover": "अल्बम कव्हर निवडा",
"select_all": "सर्व निवडा",
"select_all_duplicates": "सर्व डुप्लिकेट्स निवडा",
"select_all_in": "{group} मधील सर्व निवडा",
"select_avatar_color": "अवतारचा रंग निवडा",
"select_face": "चेहरा निवडा",
"select_featured_photo": "फिचर्ड फोटो निवडा",
"select_from_computer": "कॉम्प्युटरमधून निवडा",
"select_keep_all": "सर्व ठेवणे निवडा",
"select_library_owner": "लायब्ररी मालक निवडा",
"select_new_face": "नवा चेहरा निवडा",
"select_person_to_tag": "टॅग करण्यासाठी व्यक्ती निवडा",
"select_photos": "फोटो निवडा",
"select_trash_all": "कचरापेटीतील सर्व निवडा",
"select_user_for_sharing_page_err_album": "अल्बम तयार करण्यात अयशस्वी",
"selected": "निवडलेले",
"selected_count": "{count, plural, other {# निवडले}}",
"selected_gps_coordinates": "निवडलेल्या GPS स्थाननिर्देशांक",
"send_message": "संदेश पाठवा",
"send_welcome_email": "स्वागत ईमेल पाठवा",
"server_endpoint": "सर्व्हर एंडपॉइंट",
"server_info_box_app_version": "अॅप आवृत्ती",
"server_info_box_server_url": "सर्व्हर URL",
"server_offline": "सर्व्हर ऑफलाइन",
"server_online": "सर्व्हर ऑनलाइन",
"server_privacy": "सर्व्हर गोपनीयता",
"server_stats": "सर्व्हर आकडेवारी",
"server_version": "सर्व्हर आवृत्ती",
"set": "सेट करा",
"set_as_album_cover": "अल्बम कव्हर म्हणून सेट करा",
"set_as_featured_photo": "फिचर्ड फोटो म्हणून सेट करा",
"set_as_profile_picture": "प्रोफाइल फोटो म्हणून सेट करा",
"set_date_of_birth": "जन्मतारीख सेट करा",
"set_profile_picture": "प्रोफाइल फोटो सेट करा",
"set_slideshow_to_fullscreen": "स्लाइडशो फुलस्क्रीन करा",
"set_stack_primary_asset": "मुख्य आयटम म्हणून सेट करा",
"setting_image_viewer_help": "डीटेल व्ह्यूअर आधी लहान थंबनेल लोड करतो, नंतर (सक्षम असल्यास) मध्यम आकाराचे प्रिव्ह्यू लोड करतो, आणि शेवटी (सक्षम असल्यास) मूळ प्रतिमा लोड करतो.",
"setting_image_viewer_original_subtitle": "पूर्ण-रिझोल्यूशनची मूळ प्रतिमा लोड करण्यासाठी सक्षम करा (मोठी). डेटा वापर कमी करण्यासाठी (नेटवर्क व डिव्हाइस कॅश दोन्ही) अक्षम करा.",
"setting_image_viewer_original_title": "मूळ प्रतिमा लोड करा",
"setting_image_viewer_preview_subtitle": "मध्यम-रिझोल्यूशन प्रतिमा लोड करण्यासाठी सक्षम करा. अक्षम केल्यास थेट मूळ प्रतिमा लोड होईल किंवा फक्त थंबनेल वापरला जाईल.",
"setting_image_viewer_preview_title": "प्रिव्ह्यू प्रतिमा लोड करा",
"setting_image_viewer_title": "प्रतिमा",
"setting_languages_apply": "लागू करा",
"setting_languages_subtitle": "अॅपची भाषा बदला",
"setting_notifications_notify_failures_grace_period": "पार्श्वभूमी बॅकअप अपयशांची सूचना: {duration}",
"setting_notifications_notify_hours": "{count} तास",
"setting_notifications_notify_immediately": "तत्काळ",
"setting_notifications_notify_minutes": "{count} मिनिटे",
"setting_notifications_notify_never": "कधीच नाही",
"setting_notifications_notify_seconds": "{count} सेकंद",
"setting_notifications_single_progress_subtitle": "प्रत्येक आयटमसाठी तपशीलवार अपलोड प्रगती माहिती",
"setting_notifications_single_progress_title": "पार्श्वभूमी बॅकअपची तपशीलवार प्रगती दाखवा",
"setting_notifications_subtitle": "तुमची सूचना प्राधान्ये समायोजित करा",
"setting_notifications_total_progress_subtitle": "एकूण अपलोड प्रगती (पूर्ण/एकूण आयटम)",
"setting_notifications_total_progress_title": "पार्श्वभूमी बॅकअपची एकूण प्रगती दाखवा",
"setting_video_viewer_looping_title": "लूपिंग",
"setting_video_viewer_original_video_subtitle": "सर्व्हरवरून व्हिडिओ स्ट्रिम करताना ट्रान्सकोड उपलब्ध असला तरी मूळ व्हिडिओ प्ले करा. बफरिंग होऊ शकते. स्थानिकरीत्या उपलब्ध व्हिडिओ या सेटिंगपासून स्वतंत्रपणे मूळ गुणवत्तेत प्ले होतात.",
"setting_video_viewer_original_video_title": "मूळ व्हिडिओ सक्तीने प्ले करा",
"settings": "सेटिंग्ज",
"settings_require_restart": "ही सेटिंग लागू करण्यासाठी कृपया Immich रीस्टार्ट करा",
"settings_saved": "सेटिंग्ज जतन केल्या",
"setup_pin_code": "PIN कोड सेट करा",
"share": "शेअर करा",
"share_action_prompt": "{count} आयटम शेअर केले",
"share_add_photos": "फोटो जोडा",
"share_assets_selected": "{count} निवडले",
"share_dialog_preparing": "तयार करत आहे...",
"share_link": "शेअर दुवा",
"shared": "शेअर केले",
"shared_album_activities_input_disable": "टिप्पणी निष्क्रिय आहे",
"shared_album_activity_remove_content": "ही कृती हटवायची आहे का?",
"shared_album_activity_remove_title": "कृती हटवा",
"shared_album_section_people_action_error": "अल्बममधून बाहेर पडताना/काढताना त्रुटी",
"shared_album_section_people_action_leave": "अल्बममधून वापरकर्ता काढा",
"shared_album_section_people_action_remove_user": "अल्बममधून वापरकर्ता काढा",
"shared_album_section_people_title": "लोक",
"shared_by": "यांनी शेअर केले",
"shared_by_user": "{user} यांनी शेअर केले",
"shared_by_you": "तुमच्याकडून शेअर केले",
"shared_from_partner": "{partner} कडील फोटो",
"shared_intent_upload_button_progress_text": "{current}/{total} अपलोड झाले",
"shared_link_app_bar_title": "शेअर्ड दुवे",
"shared_link_clipboard_copied_massage": "क्लिपबोर्डवर कॉपी केले",
"shared_link_clipboard_text": "दुवा: {link}\nपासवर्ड: {password}",
"shared_link_create_error": "शेअर्ड दुवा तयार करताना त्रुटी",
"shared_link_custom_url_description": "सानुकूल URL द्वारे हा शेअर्ड दुवा उघडा",
"shared_link_edit_description_hint": "शेअरचे वर्णन प्रविष्ट करा",
"shared_link_edit_expire_after_option_day": "1 दिवस",
"shared_link_edit_expire_after_option_days": "{count} दिवस",
"shared_link_edit_expire_after_option_hour": "1 तास",
"shared_link_edit_expire_after_option_hours": "{count} तास",
"shared_link_edit_expire_after_option_minute": "1 मिनिट",
"shared_link_edit_expire_after_option_minutes": "{count} मिनिटे",
"shared_link_edit_expire_after_option_months": "{count} महिने",
"shared_link_edit_expire_after_option_year": "{count} वर्ष",
"shared_link_edit_password_hint": "शेअरचा पासवर्ड प्रविष्ट करा",
"shared_link_edit_submit_button": "दुवा अद्ययावत करा",
"shared_link_error_server_url_fetch": "सर्व्हर URL मिळू शकला नाही",
"shared_link_expires_day": "{count} दिवसात संपेल",
"shared_link_expires_days": "{count} दिवसात संपेल",
"shared_link_expires_hour": "{count} तासात संपेल",
"shared_link_expires_hours": "{count} तासांत संपेल",
"shared_link_expires_minute": "{count} मिनिटात संपेल",
"shared_link_expires_minutes": "{count} मिनिटांत संपेल",
"shared_link_expires_never": "कधीच संपत नाही ∞",
"shared_link_expires_second": "{count} सेकंदात संपेल",
"shared_link_expires_seconds": "{count} सेकंदात संपेल",
"shared_link_individual_shared": "वैयक्तिक शेअर",
"shared_link_info_chip_metadata": "EXIF (एक्सिफ)",
"shared_link_manage_links": "शेअर्ड दुवे व्यवस्थापित करा",
"shared_link_options": "शेअर्ड दुवा पर्याय",
"shared_link_password_description": "हा शेअर्ड दुवा पाहण्यासाठी पासवर्ड आवश्यक आहे",
"shared_links": "शेअर्ड दुवे",
"shared_links_description": "दुव्याद्वारे फोटो आणि व्हिडिओ शेअर करा",
"shared_photos_and_videos_count": "{assetCount, plural, other {# शेअर्ड फोटो आणि व्हिडिओ}}",
"shared_with_me": "माझ्यासोबत शेअर केलेले",
"shared_with_partner": "{partner} सोबत शेअर केले",
"sharing": "शेअरिंग",
"sharing_enter_password": "हे पृष्ठ पाहण्यासाठी कृपया पासवर्ड प्रविष्ट करा.",
"sharing_page_album": "शेअर्ड अल्बम",
"sharing_page_description": "तुमच्या नेटवर्कमधील लोकांसोबत फोटो-व्हिडिओ शेअर करण्यासाठी शेअर्ड अल्बम तयार करा.",
"sharing_page_empty_list": "रिकामी यादी",
"sharing_sidebar_description": "साइडबारमध्ये शेअरिंगचा दुवा दाखवा",
"sharing_silver_appbar_create_shared_album": "नवीन शेअर्ड अल्बम",
"sharing_silver_appbar_share_partner": "भागीदारासोबत शेअर करा",
"shift_to_permanent_delete": "अॅसेट कायमचे हटवण्यासाठी ⇧ दाबा",
"show_album_options": "अल्बम पर्याय दाखवा",
"show_albums": "अल्बम दाखवा",
"show_all_people": "सर्व लोक दाखवा",
"show_and_hide_people": "लोक दाखवा आणि लपवा",
"show_file_location": "फाइलचे स्थान दाखवा",
"show_gallery": "गॅलरी दाखवा",
"show_hidden_people": "लपवलेले लोक दाखवा",
"show_in_timeline": "टाइमलाइनमध्ये दाखवा",
"show_in_timeline_setting_description": "या वापरकर्त्याचे फोटो-व्हिडिओ तुमच्या टाइमलाइनमध्ये दाखवा",
"show_keyboard_shortcuts": "कीबोर्ड शॉर्टकट दाखवा",
"show_metadata": "मेटाडेटा दाखवा",
"show_or_hide_info": "माहिती दाखवा किंवा लपवा",
"show_password": "पासवर्ड दाखवा",
"show_person_options": "व्यक्तीचे पर्याय दाखवा",
"show_progress_bar": "प्रगती पट्टी दाखवा",
"show_search_options": "शोध पर्याय दाखवा",
"show_shared_links": "शेअर केलेले दुवे दाखवा",
"show_slideshow_transition": "स्लाइडशो ट्रांझिशन दाखवा",
"show_supporter_badge": "समर्थक बॅज",
"show_supporter_badge_description": "समर्थक बॅज दाखवा",
"shuffle": "शफल",
"sidebar": "साइडबार",
"sidebar_display_description": "साइडबारमध्ये दृश्याचा दुवा दाखवा",
"sign_out": "साइन आउट",
"sign_up": "साइन अप",
"size": "आकार",
"skip_to_content": "सामग्रीकडे जा",
"skip_to_folders": "फोल्डर्सकडे जा",
"skip_to_tags": "टॅग्सकडे जा",
"slideshow": "स्लाइडशो",
"slideshow_settings": "स्लाइडशो सेटिंग्ज",
"sort_albums_by": "अल्बम यानुसार क्रम लावा…",
"sort_created": "तयार केलेली तारीख",
"sort_items": "आयटमांची संख्या",
"sort_modified": "बदल केलेली तारीख",
"sort_newest": "अलीकडचा फोटो",
"sort_oldest": "सर्वात जुना फोटो",
"sort_people_by_similarity": "साम्यतेनुसार व्यक्तींचा क्रम लावा",
"sort_recent": "नुकताच घेतलेला फोटो",
"sort_title": "शीर्षक",
"source": "स्त्रोत",
"stack": "स्टॅक",
"stack_action_prompt": "{count} स्टॅक केले",
"stack_duplicates": "डुप्लिकेट्स स्टॅक करा",
"stack_select_one_photo": "स्टॅकसाठी एक मुख्य फोटो निवडा",
"stack_selected_photos": "निवडलेले फोटो स्टॅक करा",
"stacked_assets_count": "स्टॅक केलेले {count, plural, one {# आयटम} other {# आयटम}}",
"stacktrace": "स्टॅकट्रेस",
"start": "सुरू करा",
"start_date": "सुरुवातीची तारीख",
"state": "स्थिती",
"status": "स्टेटस",
"stop_casting": "कास्टिंग थांबवा",
"stop_motion_photo": "मोशन फोटो थांबवा",
"stop_photo_sharing": "तुमचे फोटो शेअर करणे थांबवायचे?",
"stop_photo_sharing_description": "{partner} यांना आता तुमचे फोटो पाहता येणार नाहीत.",
"stop_sharing_photos_with_user": "या वापरकर्त्यासोबत तुमचे फोटो शेअर करणे थांबवा",
"storage": "संचयन जागा",
"storage_label": "संचयन लेबल",
"storage_quota": "संचयन कोटा",
"storage_usage": "{available} पैकी {used} वापरले",
"submit": "सादर करा",
"success": "यशस्वी",
"suggestions": "सूचना",
"sunrise_on_the_beach": "समुद्रकिनाऱ्यावर सूर्योदय",
"support": "सहाय्य",
"support_and_feedback": "सहाय्य आणि अभिप्राय",
"support_third_party_description": "तुमची Immich स्थापना तृतीय-पक्ष पॅकेजद्वारे दिली आहे. तुम्हाला येणाऱ्या समस्या त्या पॅकेजमुळे असू शकतात; त्यामुळे खालील दुव्यांचा वापर करून सर्वप्रथम त्यांच्याकडे समस्या नोंदवा.",
"swap_merge_direction": "मर्ज दिशेची अदलाबदल करा",
"sync": "समक्रमण",
"sync_albums": "अल्बम समक्रमित करा",
"sync_albums_manual_subtitle": "अपलोड केलेले सर्व फोटो-व्हिडिओ निवडलेल्या बॅकअप अल्बममध्ये समक्रमित करा",
"sync_local": "स्थानिक समक्रमण",
"sync_remote": "दूरस्थ समक्रमण",
"sync_status": "समक्रमण स्थिती",
"sync_status_subtitle": "समक्रमण प्रणाली पाहा आणि व्यवस्थापित करा",
"sync_upload_album_setting_subtitle": "Immich वरील निवडलेल्या अल्बममध्ये तुमचे फोटो व व्हिडिओ तयार करा आणि अपलोड करा",
"tag": "टॅग",
"tag_assets": "आयटमना टॅग लावा",
"tag_created": "तयार केलेला टॅग: {tag}",
"tag_feature_description": "तार्किक टॅग विषयांनुसार गटबद्ध फोटो व व्हिडिओ ब्राउझ करा",
"tag_not_found_question": "टॅग सापडत नाही? <link>नवा टॅग तयार करा</link>",
"tag_people": "व्यक्तींना टॅग करा",
"tag_updated": "अद्ययावत टॅग: {tag}",
"tagged_assets": "टॅग केलेले {count, plural, one {# आयटम} other {# आयटम}}",
"tags": "टॅग्स",
"tap_to_run_job": "जॉब चालवण्यासाठी टॅप करा",
"template": "टेम्पलेट",
"theme": "थीम",
"theme_selection": "थीम निवड",
"theme_selection_description": "ब्राउझरच्या सिस्टम पसंतीनुसार थीम आपोआप लाइट/डार्क करा",
"theme_setting_asset_list_storage_indicator_title": "अॅसेट टाइल्सवर स्टोरेज निर्देशक दाखवा",
"theme_setting_asset_list_tiles_per_row_title": "प्रत्येक रांगेतील अॅसेट्सची संख्या ({count})",
"theme_setting_colorful_interface_subtitle": "बॅकग्राऊंड पृष्ठभागांवर प्राथमिक रंग लागू करा.",
"theme_setting_colorful_interface_title": "रंगीबेरंगी इंटरफेस",
"theme_setting_image_viewer_quality_subtitle": "डीटेल इमेज व्ह्यूअरची गुणवत्ता समायोजित करा",
"theme_setting_image_viewer_quality_title": "इमेज व्ह्यूअर गुणवत्ता",
"theme_setting_primary_color_subtitle": "प्राथमिक कृती व अॅक्सेंटसाठी रंग निवडा.",
"theme_setting_primary_color_title": "प्राथमिक रंग",
"theme_setting_system_primary_color_title": "सिस्टम रंग वापरा",
"theme_setting_system_theme_switch": "स्वयंचलित (सिस्टम सेटिंग्जनुसार)",
"theme_setting_theme_subtitle": "अॅपची थीम सेटिंग निवडा",
"theme_setting_three_stage_loading_subtitle": "थ्री-स्टेज लोडिंगमुळे गती वाढू शकते; परंतु नेटवर्क लोड लक्षणीय वाढतो",
"theme_setting_three_stage_loading_title": "थ्री-स्टेज लोडिंग सुरू करा",
"they_will_be_merged_together": "ते एकत्र विलीन केले जातील",
"third_party_resources": "तृतीय-पक्ष संसाधने",
"time_based_memories": "वेळ-आधारित मेमरीज",
"timeline": "टाइमलाइन",
"timezone": "वेळक्षेत्र",
"to_archive": "आर्काइव्ह करा",
"to_change_password": "परवलीचा शब्द बदला",
"to_favorite": "आवडीमध्ये जोडा",
"to_login": "लॉग इन करा",
"to_multi_select": "बहु-निवड करा",
"to_parent": "पालकाकडे जा",
"to_select": "निवडा",
"to_trash": "कचरापेटीत टाका",
"toggle_settings": "सेटिंग्ज टॉगल करा",
"total": "एकूण",
"total_usage": "एकूण वापर",
"trash": "कचरापेटी",
"trash_action_prompt": "{count} कचरापेटीत हलवले",
"trash_all": "सर्व कचरापेटीत टाका",
"trash_count": "कचरापेटी {count, number}",
"trash_delete_asset": "कचरापेटीत टाका/अॅसेट हटवा",
"trash_emptied": "कचरापेटी रिकामी केली",
"trash_no_results_message": "कचरापेटीत टाकलेले फोटो व व्हिडिओ येथे दिसतील.",
"trash_page_delete_all": "सर्व हटवा",
"trash_page_empty_trash_dialog_content": "कचरापेटी रिकामी करायची का? हे आयटम Immich मधून कायमचे हटवले जातील",
"trash_page_info": "कचरापेटीतील आयटम {days} दिवसांनंतर कायमचे हटवले जातील",
"trash_page_no_assets": "कचरापेटीत कोणतेही आयटम नाहीत",
"trash_page_restore_all": "सर्व परत आणा",
"trash_page_select_assets_btn": "आयटम निवडा",
"trash_page_title": "कचरापेटी ({count})",
"trashed_items_will_be_permanently_deleted_after": "कचरापेटीतील आयटम {days, plural, one {# दिवसांनंतर} other {# दिवसांनंतर}} कायमचे हटवले जातील.",
"troubleshoot": "समस्या निवारण",
"type": "प्रकार",
"unable_to_change_pin_code": "PIN कोड बदलता येत नाही",
"unable_to_setup_pin_code": "PIN कोड सेट करू शकत नाही",
"unarchive": "अनआर्काइव्ह करा",
"unarchive_action_prompt": "{count} आर्काइव्हमधून काढले",
"unarchived_count": "{count, plural, other {अनआर्काइव्ह #}}",
"undo": "पूर्ववत करा",
"unfavorite": "आवडीतून काढा",
"unfavorite_action_prompt": "{count} आवडीतून काढले",
"unhide_person": "व्यक्ती दर्शवा",
"unknown": "अज्ञात",
"unknown_country": "अज्ञात देश",
"unknown_year": "अज्ञात वर्ष",
"unlimited": "अमर्यादित",
"unlink_motion_video": "मोशन व्हिडिओ अनलिंक करा",
"unlink_oauth": "OAuth अनलिंक करा",
"unlinked_oauth_account": "OAuth खाते अनलिंक केले",
"unmute_memories": "मेमरीज अनम्यूट करा",
"unnamed_album": "नाव नसलेला अल्बम",
"unnamed_album_delete_confirmation": "तुम्हाला हा अल्बम खरंच हटवायचा आहे का?",
"unnamed_share": "नाव नसलेले शेअर",
"unsaved_change": "न साठवलेला बदल",
"unselect_all": "सर्व निवडी रद्द करा",
"unselect_all_duplicates": "सर्व डुप्लिकेट्सची निवड रद्द करा",
"unselect_all_in": "{group} मधील सर्व निवडी रद्द करा",
"unstack": "स्टॅक वेगळा करा",
"unstack_action_prompt": "{count} अनस्टॅक केले",
"unstacked_assets_count": "अनस्टॅक केलेले {count, plural, one {# आयटम} other {# आयटम}}",
"untagged": "टॅग नसलेले",
"up_next": "पुढे",
"update_location_action_prompt": "निवडलेल्या {count} आयटमचे स्थान याने अद्ययावत करा:",
"updated_at": "अद्ययावत केले",
"updated_password": "परवलीचा शब्द अद्ययावत केला",
"upload": "अपलोड",
"upload_action_prompt": "अपलोडसाठी {count} रांगेत",
"upload_concurrency": "अपलोड समांतरता",
"upload_details": "अपलोड तपशील",
"upload_dialog_info": "निवडलेले आयटम सर्व्हरवर बॅकअप करायचे का?",
"upload_dialog_title": "अॅसेट अपलोड करा",
"upload_errors": "अपलोड पूर्ण झाले; {count, plural, one {# त्रुटी} other {# त्रुटी}} आढळल्या. नवीन अपलोड आयटम पाहण्यासाठी पृष्ठ रीफ्रेश करा.",
"upload_finished": "अपलोड पूर्ण",
"upload_progress": "उर्वरित {remaining, number} — प्रक्रिया झालेले {processed, number}/{total, number}",
"upload_skipped_duplicates": "वगळले {count, plural, one {# डुप्लिकेट आयटम} other {# डुप्लिकेट आयटम}}",
"upload_status_duplicates": "डुप्लिकेट",
"upload_status_errors": "त्रुटी",
"upload_status_uploaded": "अपलोड झाले",
"upload_success": "अपलोड यशस्वी. नवीन अपलोड आयटम दिसण्यासाठी पृष्ठ रीफ्रेश करा.",
"upload_to_immich": "Immich वर अपलोड करा ({count})",
"uploading": "अपलोड होत आहे",
"uploading_media": "माध्यमे अपलोड होत आहेत",
"url": "URL",
"usage": "वापर",
"use_biometric": "बायोमेट्रिक वापरा",
"use_current_connection": "सध्याचे कनेक्शन वापरा",
"use_custom_date_range": "याऐवजी सानुकूल दिनांक श्रेणी वापरा",
"user": "वापरकर्ता",
"user_has_been_deleted": "हा वापरकर्ता हटविला गेला आहे.",
"user_id": "वापरकर्ता आयडी",
"user_liked": "{user} यांना {type, select, photo {हा फोटो} video {हा व्हिडिओ} asset {हा आयटम} other {हे}} आवडले",
"user_pin_code_settings": "PIN कोड",
"user_pin_code_settings_description": "तुमचा PIN कोड व्यवस्थापित करा",
"user_privacy": "वापरकर्ता गोपनीयता",
"user_purchase_settings": "खरेदी",
"user_purchase_settings_description": "तुमची खरेदी व्यवस्थापित करा",
"user_role_set": "{user} यांना {role} म्हणून सेट करा",
"user_usage_detail": "वापरकर्त्याच्या वापराचा तपशील",
"user_usage_stats": "खात्याच्या वापराच्या सांख्यिकी",
"user_usage_stats_description": "खात्याच्या वापराच्या सांख्यिकी पहा",
"username": "वापरकर्तानाव",
"users": "वापरकर्ते",
"users_added_to_album_count": "अल्बममध्ये {count, plural, one {# वापरकर्ता जोडला} other {# वापरकर्ते जोडले}}",
"utilities": "उपयुक्तता",
"validate": "तपासा",
"validate_endpoint_error": "कृपया वैध URL प्रविष्ट करा",
"variables": "चल",
"version": "आवृत्ती",
"version_announcement_closing": "तुमचा मित्र, अ‍ॅलेक्स",
"version_announcement_message": "नमस्कार! Immich ची नवी आवृत्ती उपलब्ध आहे. तुमची संरचना अद्ययावत आणि बिनचूक राहावी यासाठी कृपया काही वेळ काढून <link>रिलीज नोट्स</link> वाचा, विशेषतः तुम्ही WatchTower किंवा अद्ययावत प्रक्रिया स्वयंचलितपणे हाताळणारी कोणतीही व्यवस्था वापरत असाल तर.",
"version_history": "आवृत्ती इतिहास",
"version_history_item": "{date} रोजी {version} स्थापित केली",
"video": "व्हिडिओ",
"video_hover_setting": "हावर केल्यावर व्हिडिओ थंबनेल प्ले करा",
"video_hover_setting_description": "आयटमवर माऊस नेल्यावर व्हिडिओ थंबनेल प्ले होईल. पर्याय बंद असला तरी प्ले चिन्हावर हावर केल्यास प्लेबॅक सुरू करता येईल.",
"videos": "व्हिडिओ",
"videos_count": "{count, plural, one {# व्हिडिओ} other {# व्हिडिओ}}",
"view": "पहा",
"view_album": "अल्बम पहा",
"view_all": "सर्व पहा",
"view_all_users": "सर्व वापरकर्ते पहा",
"view_details": "तपशील पहा",
"view_in_timeline": "टाइमलाइनमध्ये पहा",
"view_link": "दुवा पहा",
"view_links": "दुवे पहा",
"view_name": "पहा",
"view_next_asset": "पुढील आयटम पहा",
"view_previous_asset": "मागील आयटम पहा",
"view_qr_code": "QR कोड पहा",
"view_similar_photos": "समान फोटो पहा",
"view_stack": "स्टॅक पहा",
"view_user": "वापरकर्ता पहा",
"viewer_remove_from_stack": "स्टॅकमधून काढा",
"viewer_stack_use_as_main_asset": "मुख्य आयटम म्हणून वापरा",
"viewer_unstack": "स्टॅक वेगळा करा",
"visibility_changed": "दृश्यता {count, plural, one {# व्यक्तीसाठी बदलली} other {# व्यक्तींसाठी बदलली}}",
"waiting": "प्रतीक्षेत",
"warning": "चेतावणी",
"week": "आठवडा",

View File

@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "Mobilapp er utdatert. Vennligst oppdater til nyeste versjon.",
"profile_drawer_client_server_up_to_date": "Klient og server er oppdatert",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Skrivebeskyttet modus er aktivert. Dobbelttrykk på brukerens avatarikon for å avslutte.",
"profile_drawer_readonly_mode": "Skrivebeskyttet modus er aktivert. Langttrykk på brukerens avatarikon for å avslutte.",
"profile_drawer_server_out_of_date_major": "Server er utdatert. Vennligst oppdater til nyeste versjon.",
"profile_drawer_server_out_of_date_minor": "Server er utdatert. Vennligst oppdater til nyeste versjon.",
"profile_image_of_user": "Profil bilde av {user}",
@@ -1917,6 +1917,8 @@
"sync_albums_manual_subtitle": "Synkroniser alle opplastede videoer og bilder til det valgte backupalbumet",
"sync_local": "Synkroniser lokalt",
"sync_remote": "Synkroniser eksternt",
"sync_status": "Synkroniseringsstatus",
"sync_status_subtitle": "Vis og håndter synkronisering",
"sync_upload_album_setting_subtitle": "Opprett og last opp dine bilder og videoer til det valgte albumet på Immich",
"tag": "Tagg",
"tag_assets": "Merk ressurser",
@@ -1976,6 +1978,7 @@
"trash_page_select_assets_btn": "Velg objekter",
"trash_page_title": "Søppelbøtte ({count})",
"trashed_items_will_be_permanently_deleted_after": "Elementer i papirkurven vil bli permanent slettet etter {days, plural, one {# dag} other {# dager}}.",
"troubleshoot": "Feilsøk",
"type": "Type",
"unable_to_change_pin_code": "Klarte ikke å endre PIN-kode",
"unable_to_setup_pin_code": "Klarte ikke å sette opp PINkode",

View File

@@ -708,7 +708,7 @@
"control_bottom_app_bar_edit_time": "Datum & tijd bewerken",
"control_bottom_app_bar_share_link": "Link delen",
"control_bottom_app_bar_share_to": "Delen met",
"control_bottom_app_bar_trash_from_immich": "Verwijderen uit Immich",
"control_bottom_app_bar_trash_from_immich": "Verwijderen van Immich",
"copied_image_to_clipboard": "Afbeelding gekopieerd naar klembord.",
"copied_to_clipboard": "Gekopieerd naar klembord!",
"copy_error": "Fout bij kopiëren",
@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "Mobiele app is verouderd. Werk bij naar de nieuwste subversie.",
"profile_drawer_client_server_up_to_date": "App en server zijn up-to-date",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Alleen-lezen-modus ingeschakeld. Dubbeltik op het avatarpictogram van de gebruiker om te verlaten.",
"profile_drawer_readonly_mode": "Alleen-lezen-modus ingeschakeld. Druk lang op je profielfoto om te verlaten.",
"profile_drawer_server_out_of_date_major": "Server is verouderd. Werk bij naar de nieuwste hoofdversie.",
"profile_drawer_server_out_of_date_minor": "Server is verouderd. Werk bij naar de nieuwste subversie.",
"profile_image_of_user": "Profielfoto van {user}",
@@ -1640,6 +1640,7 @@
"restore_user": "Gebruiker herstellen",
"restored_asset": "Item hersteld",
"resume": "Hervatten",
"resume_paused_jobs": "Hervat {count, plural, one {# gepauseerde taak} other {# gepauseerde taken}}",
"retry_upload": "Opnieuw uploaden",
"review_duplicates": "Controleer duplicaten",
"review_large_files": "Grote bestanden beoordelen",
@@ -1916,6 +1917,8 @@
"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_status": "Sync Status",
"sync_status_subtitle": "Bekijk en beheer het synchronisatie systeem",
"sync_upload_album_setting_subtitle": "Maak en upload je foto's en video's naar de geselecteerde albums op Immich",
"tag": "Tag",
"tag_assets": "Items taggen",
@@ -1975,6 +1978,7 @@
"trash_page_select_assets_btn": "Selecteer items",
"trash_page_title": "Prullenbak ({count})",
"trashed_items_will_be_permanently_deleted_after": "Items in de prullenbak worden na {days, plural, one {# dag} other {# dagen}} permanent verwijderd.",
"troubleshoot": "Problemen oplossen",
"type": "Type",
"unable_to_change_pin_code": "PIN code kan niet gewijzigd worden",
"unable_to_setup_pin_code": "PIN code kan niet ingesteld worden",

View File

@@ -443,7 +443,7 @@
"albums_default_sort_order": "Domyślna kolejność sortowania w albumach",
"albums_default_sort_order_description": "Początkowa kolejność sortowania zasobów przy tworzeniu nowych albumów.",
"albums_feature_description": "Kolekcje zasobów, które można udostępniać innym użytkownikom.",
"albums_on_device_count": "Albumów na urzadzeniu ({count})",
"albums_on_device_count": "Albumy na urządzeniu ({count})",
"all": "Wszystkie",
"all_albums": "Wszystkie albumy",
"all_people": "Wszystkie osoby",
@@ -504,7 +504,7 @@
"assets_added_count": "Dodano {count, plural, one {# zasób} few {# zasoby} other {# zasobów}}",
"assets_added_to_album_count": "Dodano {count, plural, one {# zasób} few {# zasoby} other {# zasobów}} do albumu",
"assets_added_to_albums_count": "Dodano {assetTotal, plural, one {# zasób} few {# zasoby} other {# zasobów}} do {albumTotal, plural, one {# albumu} other {# albumów}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {sztuka Elementu} other {szt. Elementów}} nie może być dodana do albumu",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Zasób nie może zostać dodany} other {Zasoby nie mogą zostać dodane}} do albumu",
"assets_cannot_be_added_to_albums": "{count, plural, one {Zasób nie może być dodany} other {Zasoby nie mogą być dodane}} do żadnego z albumów",
"assets_count": "{count, plural, one {# zasób} few {# zasoby} other {# zasobów}}",
"assets_deleted_permanently": "{count} zostało trwale usuniętych",
@@ -521,7 +521,7 @@
"assets_trashed": "{count} szt. zostało wrzucone do kosza",
"assets_trashed_count": "Wrzucono do kosza {count, plural, one {# zasób} few {# zasoby} other {# zasobów}}",
"assets_trashed_from_server": "{count} szt. usuniętych z serwera Immich",
"assets_were_part_of_album_count": "{count, plural, one {Zasób był} few {Zasoby były} many {Zasobów było} other {Zasobów było}} już częścią albumu",
"assets_were_part_of_album_count": "{count, plural, one {Zasób był} other {Zasoby były}} już częścią albumu",
"assets_were_part_of_albums_count": "{count, plural, one {Zasób był} other {Zasoby były}} już częścią albumów",
"authorized_devices": "Autoryzowane urządzenia",
"automatic_endpoint_switching_subtitle": "Połącz się lokalnie przez wyznaczoną sieć Wi-Fi, jeśli jest dostępna, i korzystaj z alternatywnych połączeń gdzie indziej",
@@ -535,7 +535,7 @@
"backup_album_selection_page_albums_device": "Albumy na urządzeniu ({count})",
"backup_album_selection_page_albums_tap": "Stuknij, aby włączyć, stuknij dwukrotnie, aby wykluczyć",
"backup_album_selection_page_assets_scatter": "Pliki mogą być rozproszone w wielu albumach. Dzięki temu albumy mogą być włączane lub wyłączane podczas procesu tworzenia kopii zapasowej.",
"backup_album_selection_page_select_albums": "Zaznacz albumy",
"backup_album_selection_page_select_albums": "Wybierz albumy",
"backup_album_selection_page_selection_info": "Info o wyborze",
"backup_album_selection_page_total_assets": "Łącznie unikalnych plików",
"backup_all": "Wszystkie",
@@ -564,7 +564,7 @@
"backup_controller_page_background_turn_on": "Włącz usługę w tle",
"backup_controller_page_background_wifi": "Tylko Wi-Fi",
"backup_controller_page_backup": "Kopia zapasowa",
"backup_controller_page_backup_selected": "Zaznaczone: ",
"backup_controller_page_backup_selected": "Wybrane: ",
"backup_controller_page_backup_sub": "Zdjęcia i filmy z utworzoną kopią zapasową",
"backup_controller_page_created": "Utworzono dnia: {date}",
"backup_controller_page_desc_backup": "Włącz kopię zapasową na pierwszym planie, aby automatycznie przesyłać nowe zasoby na serwer po otworzeniu aplikacji.",
@@ -573,7 +573,7 @@
"backup_controller_page_filename": "Nazwa pliku: {filename} [{size}]",
"backup_controller_page_id": "ID: {id}",
"backup_controller_page_info": "Informacje o kopii zapasowej",
"backup_controller_page_none_selected": "Brak wybranych",
"backup_controller_page_none_selected": "Nic nie wybrano",
"backup_controller_page_remainder": "Pozostałe",
"backup_controller_page_remainder_sub": "Pozostałe zdjęcia i filmy wybrane do wykonania kopii zapasowej",
"backup_controller_page_server_storage": "Pamięć Serwera",
@@ -638,7 +638,7 @@
"cast": "Odtwórz na telewizorze",
"cast_description": "Skonfiguruj dostępne cele do przesyłania",
"change_date": "Zmień datę",
"change_description": "Zmiana opisu",
"change_description": "Zmi opis",
"change_display_order": "Zmień kolejność wyświetlania",
"change_expiration_time": "Zmień czas ważności",
"change_location": "Zmień lokalizację",
@@ -691,7 +691,7 @@
"confirm_admin_password": "Potwierdź Hasło Administratora",
"confirm_delete_face": "Czy na pewno chcesz usunąć twarz {name} z zasobów?",
"confirm_delete_shared_link": "Czy na pewno chcesz usunąć ten udostępniony link?",
"confirm_keep_this_delete_others": "Wszystkie inne zasoby zostaną usunięte poza tym zasobem. Czy jesteś pewien, że chcesz kontynuować?",
"confirm_keep_this_delete_others": "Wszystkie inne zasoby w tym stosie, z wyjątkiem tego zasobu, zostaną usunięte. Czy jesteś pewien, że chcesz kontynuować?",
"confirm_new_pin_code": "Potwierdź nowy kod PIN",
"confirm_password": "Potwierdź hasło",
"confirm_tag_face": "Chcesz dodać do tej twarzy etykietę {name}?",
@@ -708,7 +708,7 @@
"control_bottom_app_bar_edit_time": "Edytuj datę i godzinę",
"control_bottom_app_bar_share_link": "Udostępnij link",
"control_bottom_app_bar_share_to": "Wyślij",
"control_bottom_app_bar_trash_from_immich": "Przenieść do kosza",
"control_bottom_app_bar_trash_from_immich": "Przenieś do kosza",
"copied_image_to_clipboard": "Skopiowano obraz do schowka.",
"copied_to_clipboard": "Skopiowano do schowka!",
"copy_error": "Błąd kopiowania",
@@ -786,7 +786,7 @@
"delete_local_action_prompt": "{count} lokalnie usunięto",
"delete_local_dialog_ok_backed_up_only": "Usuń tylko kopię zapasową",
"delete_local_dialog_ok_force": "Usuń mimo to",
"delete_others": "Usuń inne",
"delete_others": "Usuń pozostałe",
"delete_permanently": "Usuń trwale",
"delete_permanently_action_prompt": "{count} trwale usuniętych",
"delete_shared_link": "Usuń udostępniony link",
@@ -898,7 +898,7 @@
"cannot_navigate_previous_asset": "Nie można przejść do poprzedniego zasobu",
"cant_apply_changes": "Nie można zastosować zmian",
"cant_change_activity": "Nie można {enabled, select, true {wyłączyć} other {włączyć}} aktywności",
"cant_change_asset_favorite": "Nie można zmienić ulubionego dla zasobu",
"cant_change_asset_favorite": "Nie można zmienić statusu ulubionego dla zasobu",
"cant_change_metadata_assets_count": "Nie można zmienić metadanych {count, plural, one {# zasobu} other {# zasobów}}",
"cant_get_faces": "Nie można pozyskać twarzy",
"cant_get_number_of_comments": "Nie można uzyskać liczby komentarzy",
@@ -923,7 +923,7 @@
"failed_to_load_people": "Nie udało się pobrać ludzi",
"failed_to_remove_product_key": "Nie udało się usunąć klucza produktu",
"failed_to_reset_pin_code": "Nie udało się zresetować kodu PIN",
"failed_to_stack_assets": "Nie udało się zestawić zasobów",
"failed_to_stack_assets": "Nie udało się utworzyć stosu z zasobów",
"failed_to_unstack_assets": "Nie udało się rozdzielić zasobów",
"failed_to_update_notification_status": "Nie udało się zaktualizować stanu powiadomienia",
"import_path_already_exists": "Ta ścieżka importu już istnieje.",
@@ -1151,7 +1151,7 @@
"immich_web_interface": "Interfejs internetowy Immich",
"import_from_json": "Wczytaj z JSON",
"import_path": "Ścieżka importu",
"in_albums": "W {count, plural, one {# album} other {# albumy}}",
"in_albums": "W {count, plural, one {# albumie} other {# albumach}}",
"in_archive": "W archiwum",
"include_archived": "Uwzględnij zarchiwizowane",
"include_shared_albums": "Uwzględnij udostępnione albumy",
@@ -1175,11 +1175,11 @@
"ios_debug_info_no_sync_yet": "Nie uruchomiono jeszcze żadnego zadania synchronizacji w tle",
"ios_debug_info_processes_queued": "{count, plural, one {{count} proces w tle w kolejce} few {{count} procesy w tle w kolejce} other {{count} procesów w tle w kolejce}}",
"ios_debug_info_processing_ran_at": "Przetwarzanie przebiegło {dateTime}",
"items_count": "{count, plural, one {# element} other {# elementy}}",
"items_count": "{count, plural, one {# element} few {# elementy} other {# elementów}}",
"jobs": "Zadania",
"keep": "Zachowaj",
"keep_all": "Zachowaj wszystko",
"keep_this_delete_others": "Zachowaj to, usuń inne",
"keep_this_delete_others": "Zachowaj to, usuń pozostałe",
"kept_this_deleted_others": "Zachowano ten zasób i usunięto {count, plural, one {#zasób} other {#zasoby}}",
"keyboard_shortcuts": "Skróty klawiaturowe",
"language": "Język",
@@ -1459,7 +1459,7 @@
"permanent_deletion_warning_setting_description": "Pokaż ostrzeżenie przy trwałym usuwaniu zasobów",
"permanently_delete": "Usuń trwale",
"permanently_delete_assets_count": "Trwale usuń {count, plural, one {zasób} few {zasoby} many {zasobów} other {zasobów}}",
"permanently_delete_assets_prompt": "Czy na pewno chcesz trwale usunąć {count, plural, one {ten zasób?} other {te <b>#</b> zasoby?}} Spowoduje to również usunięcie {count, plural, one {go z jego} other {ich z ich}} album(ów).",
"permanently_delete_assets_prompt": "Czy na pewno chcesz trwale usunąć {count, plural, one {ten zasób?} few {te <b>#</b> zasoby?} other {te <b>#</b> zasobów?}} Spowoduje to również usunięcie {count, plural, one {go z jego} other {ich z ich}} album(ów).",
"permanently_deleted_asset": "Pomyślnie trwale usunięto zasób",
"permanently_deleted_assets_count": "Trwale usunięto {count, plural, one {# zasób} other {# zasobów}}",
"permission": "Pozwolenie",
@@ -1589,7 +1589,7 @@
"remote": "Zdalny",
"remote_assets": "Zasoby zdalne",
"remove": "Usuń",
"remove_assets_album_confirmation": "Czy na pewno chcesz usunąć {count, plural, one {# zasób} other {# zasoby}} z albumu?",
"remove_assets_album_confirmation": "Czy na pewno chcesz usunąć {count, plural, one {# zasób} few {# zasoby} other {# zasobów}} z albumu?",
"remove_assets_shared_link_confirmation": "Czy na pewno chcesz usunąć {count, plural, one {# zasób} other {# zasoby}} z tego udostępnionego linku?",
"remove_assets_title": "Usunąć zasoby?",
"remove_custom_date_range": "Usuń niestandardowy zakres dat",
@@ -1712,7 +1712,7 @@
"search_tags": "Wyszukaj etykiety...",
"search_timezone": "Wyszukaj strefę czasową...",
"search_type": "Wyszukaj w",
"search_your_photos": "Szukaj swoich zdjęć",
"search_your_photos": "Przeszukaj swoje zdjęcia",
"searching_locales": "Wyszukaj region...",
"second": "Sekunda",
"see_all_people": "Zobacz wszystkie osoby",
@@ -1732,7 +1732,7 @@
"select_photos": "Wybierz zdjęcia",
"select_trash_all": "Zaznacz wszystko do kosza",
"select_user_for_sharing_page_err_album": "Nie udało się utworzyć albumu",
"selected": "Zaznaczone",
"selected": "Wybrane",
"selected_count": "{count, plural, other {# wybrane}}",
"selected_gps_coordinates": "Wybrane Współrzędne GPS",
"send_message": "Wyślij wiadomość",
@@ -1887,9 +1887,9 @@
"stack": "Stos",
"stack_action_prompt": "{count} zgrupowano",
"stack_duplicates": "Stos duplikatów",
"stack_select_one_photo": "Wybierz jedno główne zdjęcie do stosu",
"stack_selected_photos": "Układaj wybrane zdjęcia",
"stacked_assets_count": "Ułożone {count, plural, one {# zasób} other{# zasoby}}",
"stack_select_one_photo": "Wybierz jedno główne zdjęcie dla stosu",
"stack_selected_photos": "Utwórz stos z wybranych zdjęć",
"stacked_assets_count": "Utworzono stos z {count, plural, one {# zasobu} other {# zasobów}}",
"stacktrace": "Ślad stosu",
"start": "Start",
"start_date": "Od dnia",
@@ -1952,7 +1952,7 @@
"time_based_memories": "Wspomnienia oparte na czasie",
"timeline": "Oś czasu",
"timezone": "Strefa czasowa",
"to_archive": "Archiwum",
"to_archive": "Zarchiwizuj",
"to_change_password": "Zmień hasło",
"to_favorite": "Dodaj do ulubionych",
"to_login": "Zaloguj się",
@@ -1966,7 +1966,7 @@
"trash": "Kosz",
"trash_action_prompt": "{count} przeniesione do kosza",
"trash_all": "Usuń wszystkie",
"trash_count": "Kosz {count, number}",
"trash_count": "Usuń {count, number}",
"trash_delete_asset": "Kosz/Usuń zasób",
"trash_emptied": "Opróżnione śmieci",
"trash_no_results_message": "Tu znajdziesz wyrzucone zdjęcia i filmy.",
@@ -1982,7 +1982,7 @@
"type": "Typ",
"unable_to_change_pin_code": "Nie można zmienić kodu PIN",
"unable_to_setup_pin_code": "Nie można ustawić kodu PIN",
"unarchive": "Cofnij archiwizację",
"unarchive": "Przywróć z archiwum",
"unarchive_action_prompt": "{count} usunięto z archiwum",
"unarchived_count": "{count, plural, one {# cofnięta archiwizacja} few {# cofnięte archiwizacje} other {# cofniętych archiwizacji}}",
"undo": "Cofnij",
@@ -2004,9 +2004,9 @@
"unselect_all": "Odznacz wszystko",
"unselect_all_duplicates": "Odznacz wszystkie duplikaty",
"unselect_all_in": "Odznacz wszystkie w {group}",
"unstack": "Rozłóż stos",
"unstack_action_prompt": "{count} odgrupowano",
"unstacked_assets_count": "{count, plural, one {Rozłożony # zasób} few {Rozłożone # zasoby} other {Rozłożonych # zasobów}}",
"unstack": "Rozdziel stos",
"unstack_action_prompt": "{count} rozdzielono",
"unstacked_assets_count": "Rozdzielono {count, plural, one {# zasób} few {# zasoby} other {# zasobów}}",
"untagged": "Nieoznaczone",
"up_next": "Do następnego",
"update_location_action_prompt": "Zaktualizuj lokalizację {count} wybranych zasobów na:",
@@ -2077,11 +2077,11 @@
"view_previous_asset": "Wyświetl poprzedni zasób",
"view_qr_code": "Pokaż kod QR",
"view_similar_photos": "Zobacz podobne zdjęcia",
"view_stack": "Zobacz Ułożenie",
"view_stack": "Zobacz stos",
"view_user": "Wyświetl użytkownika",
"viewer_remove_from_stack": "Usuń ze stosu",
"viewer_stack_use_as_main_asset": "Użyj jako głównego zasobu",
"viewer_unstack": "Rozłóż Stos",
"viewer_unstack": "Rozdziel stos",
"visibility_changed": "Zmieniono widoczność dla {count, plural, one {# osoby} other {# osób}}",
"waiting": "Oczekujące",
"warning": "Ostrzeżenie",

View File

@@ -1412,6 +1412,8 @@
"open_the_search_filters": "Abrir os filtros de pesquisa",
"options": "Opções",
"or": "ou",
"organize_into_albums": "Organizar em álbuns",
"organize_into_albums_description": "Colocar fotos existentes em álbuns utilizando as definições atuais de sincronização",
"organize_your_library": "Organizar a sua biblioteca",
"original": "original",
"other": "Outro",
@@ -1513,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "O aplicativo está desatualizado. Por favor, atualize para a versão mais recente.",
"profile_drawer_client_server_up_to_date": "Cliente e Servidor atualizados",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Modo somente leitura activado. Toque duas vezes no ícone do avatar do utilizador para sair.",
"profile_drawer_readonly_mode": "Modo somente leitura ativado. Toque duas vezes no ícone do avatar do utilizador para sair.",
"profile_drawer_server_out_of_date_major": "O servidor está desatualizado. Atualize para a versão principal mais recente.",
"profile_drawer_server_out_of_date_minor": "O servidor está desatualizado. Atualize para a versão mais recente.",
"profile_image_of_user": "Imagem de perfil de {user}",
@@ -1552,6 +1554,7 @@
"purchase_server_description_2": "Status de apoiante",
"purchase_server_title": "Servidor",
"purchase_settings_server_activated": "A chave de produto do servidor é gerida pelo administrador",
"query_asset_id": "Consultar ID do recurso",
"queue_status": "Em fila {count}/{total}",
"rating": "Classificação por estrelas",
"rating_clear": "Limpar classificação",
@@ -1637,6 +1640,7 @@
"restore_user": "Restaurar utilizador",
"restored_asset": "Ficheiro restaurado",
"resume": "Continuar",
"resume_paused_jobs": "Continuar {count, plural, one {# trabalho em pausa} other {# trabalhos pausados}}",
"retry_upload": "Tentar carregar novamente",
"review_duplicates": "Rever itens duplicados",
"review_large_files": "Rever arquivos grandes",
@@ -1730,7 +1734,7 @@
"select_user_for_sharing_page_err_album": "Ocorreu um erro ao criar o álbum",
"selected": "Selecionados",
"selected_count": "{count, plural, other {# selecionados}}",
"selected_gps_coordinates": "coordenadas gps seleccionadas",
"selected_gps_coordinates": "Coordenadas GPS selecionadas",
"send_message": "Enviar mensagem",
"send_welcome_email": "Enviar E-mail de boas vindas",
"server_endpoint": "URL do servidor",
@@ -1913,6 +1917,8 @@
"sync_albums_manual_subtitle": "Sincronizar todas as fotos e vídeos enviados para o álbum de backup selecionado",
"sync_local": "Sincronização Local",
"sync_remote": "Sincronização Remota",
"sync_status": "Status da sincronização",
"sync_status_subtitle": "Ver e gerir o sistema de sincronização",
"sync_upload_album_setting_subtitle": "Crie e envie suas fotos e vídeos para o álbum selecionado no Immich",
"tag": "Etiqueta",
"tag_assets": "Etiquetar ficheiros",
@@ -1972,6 +1978,7 @@
"trash_page_select_assets_btn": "Selecionar arquivos",
"trash_page_title": "Reciclagem ({count})",
"trashed_items_will_be_permanently_deleted_after": "Os itens da reciclagem são eliminados permanentemente após {days, plural, one {# dia} other {# dias}}.",
"troubleshoot": "Diagnosticar problemas",
"type": "Tipo",
"unable_to_change_pin_code": "Não foi possível alterar o código PIN",
"unable_to_setup_pin_code": "Não foi possível configurar o código PIN",
@@ -2069,6 +2076,7 @@
"view_next_asset": "Ver próximo ficheiro",
"view_previous_asset": "Ver ficheiro anterior",
"view_qr_code": "Ver código QR",
"view_similar_photos": "Ver fotos similares",
"view_stack": "Ver pilha",
"view_user": "Ver utilizador",
"viewer_remove_from_stack": "Remover da pilha",

View File

@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "O aplicativo está desatualizado. Por favor, atualize para a versão mais recente.",
"profile_drawer_client_server_up_to_date": "Cliente e Servidor estão atualizados",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Modo apenas visualização ativado. Toque duas vezes na foto do usuário para sair deste modo.",
"profile_drawer_readonly_mode": "Modo apenas leitura habilidato. Dê um toque prolongado na foto do usuário para sair deste modo.",
"profile_drawer_server_out_of_date_major": "O servidor está desatualizado. Atualize para a versão principal mais recente.",
"profile_drawer_server_out_of_date_minor": "O servidor está desatualizado. Atualize para a versão mais recente.",
"profile_image_of_user": "Imagem do perfil de {user}",
@@ -1640,6 +1640,7 @@
"restore_user": "Restaurar usuário",
"restored_asset": "Arquivo restaurado",
"resume": "Continuar",
"resume_paused_jobs": "Retomar {count, plural, one {# paused job} other {# paused jobs}}",
"retry_upload": "Tentar enviar novamente",
"review_duplicates": "Revisar duplicidade",
"review_large_files": "Ver arquivos grandes",
@@ -1916,6 +1917,8 @@
"sync_albums_manual_subtitle": "Sincronize todos as fotos e vídeos enviados para os álbuns de backup selecionados",
"sync_local": "Sincronização Local",
"sync_remote": "Sincronização Remota",
"sync_status": "Status da Sincronização",
"sync_status_subtitle": "Ver e gerenciar o sistema de sincronização",
"sync_upload_album_setting_subtitle": "Crie e envie suas fotos e vídeos para o álbum selecionado no Immich",
"tag": "Marcador",
"tag_assets": "Marcar arquivos",
@@ -1975,6 +1978,7 @@
"trash_page_select_assets_btn": "Selecionar arquivos",
"trash_page_title": "Lixeira ({count})",
"trashed_items_will_be_permanently_deleted_after": "Os itens da lixeira serão deletados permanentemente após {days, plural, one {# dia} other {# dias}}.",
"troubleshoot": "Diagnosticar",
"type": "Tipo",
"unable_to_change_pin_code": "Não foi possível alterar o código PIN",
"unable_to_setup_pin_code": "Não foi possível criar o código PIN",

View File

@@ -35,7 +35,7 @@
"add_url": "Добавить URL",
"added_to_archive": "Добавлено в архив",
"added_to_favorites": "Добавлено в избранное",
"added_to_favorites_count": "Добавлено{count, number} в избранное",
"added_to_favorites_count": "{count, plural, one {# объект добавлен} many {# объектов добавлено} other {# объекта добавлено}} в избранное",
"admin": {
"add_exclusion_pattern_description": "Добавьте шаблоны исключений. Поддерживаются символы подстановки *, ** и ?. Чтобы игнорировать все файлы в любом каталоге с именем \"Raw\", укажите \"**/Raw/**\". Чтобы игнорировать все файлы, заканчивающиеся на \".tif\", используйте \"**/*.tif\". Чтобы игнорировать путь целиком, укажите \"/path/to/ignore/**\".",
"admin_user": "Администратор",
@@ -396,7 +396,7 @@
"advanced_settings_prefer_remote_title": "Предпочитать фото на сервере",
"advanced_settings_proxy_headers_subtitle": "Определите заголовки прокси-сервера, которые Immich должен отправлять с каждым сетевым запросом",
"advanced_settings_proxy_headers_title": "Заголовки прокси",
"advanced_settings_readonly_mode_subtitle": "Включает режим «только просмотр», в котором можно только просматривать объекты. Функции выбора нескольких объектов, публикации, трансляции и удаления будут недоступны. Включить/отключить режим «только просмотр» можно с помощью значка аватара пользователя на главном экране.",
"advanced_settings_readonly_mode_subtitle": "Включает режим, в котором можно только просматривать объекты. Функции выбора нескольких объектов, публикации, трансляции и удаления будут недоступны. Включить/отключить этот режим можно удерживая значок аватара пользователя на главном экране.",
"advanced_settings_readonly_mode_title": "Режим «только просмотр»",
"advanced_settings_self_signed_ssl_subtitle": "Пропускать проверку SSL-сертификата сервера. Требуется для самоподписанных сертификатов.",
"advanced_settings_self_signed_ssl_title": "Разрешить самоподписанные SSL-сертификаты",
@@ -448,7 +448,7 @@
"all_albums": "Все альбомы",
"all_people": "Все люди",
"all_videos": "Все видео",
"allow_dark_mode": "Разрешить темный режим",
"allow_dark_mode": "Разрешить тёмный режим",
"allow_edits": "Разрешить редактирование",
"allow_public_user_to_download": "Разрешить скачивание",
"allow_public_user_to_upload": "Разрешить добавление файлов",
@@ -534,9 +534,9 @@
"backup": "Резервное копирование",
"backup_album_selection_page_albums_device": "Альбомы на устройстве ({count})",
"backup_album_selection_page_albums_tap": "Нажмите, чтобы включить, дважды, чтобы исключить",
"backup_album_selection_page_assets_scatter": "Ваши изображения и видео могут находиться в разных альбомах. Вы можете выбрать, какие альбомы включить, а какие исключить из резервного копирования.",
"backup_album_selection_page_assets_scatter": "Ваши фото и видео могут находиться в разных альбомах/папках на устройстве. Вы можете выбрать, какие альбомы включить, а какие исключить из резервного копирования.",
"backup_album_selection_page_select_albums": "Выбор альбомов",
"backup_album_selection_page_selection_info": "Информация о выборе",
"backup_album_selection_page_selection_info": "Выбранные альбомы",
"backup_album_selection_page_total_assets": "Всего уникальных объектов",
"backup_all": "Все",
"backup_background_service_backup_failed_message": "Не удалось выполнить резервное копирование. Повторная попытка…",
@@ -546,7 +546,7 @@
"backup_background_service_error_title": "Ошибка резервного копирования",
"backup_background_service_in_progress_notification": "Резервное копирование объектов…",
"backup_background_service_upload_failure_notification": "Ошибка загрузки {filename}",
"backup_controller_page_albums": "Резервное копирование альбомов",
"backup_controller_page_albums": "Альбомы",
"backup_controller_page_background_app_refresh_disabled_content": "Включите фоновое обновление приложения в Настройки > Общие > Фоновое обновление приложений, чтобы использовать фоновое резервное копирование.",
"backup_controller_page_background_app_refresh_disabled_title": "Фоновое обновление отключено",
"backup_controller_page_background_app_refresh_enable_button_text": "Перейти в настройки",
@@ -563,8 +563,8 @@
"backup_controller_page_background_turn_off": "Выключить фоновую службу",
"backup_controller_page_background_turn_on": "Включить фоновую службу",
"backup_controller_page_background_wifi": "Только через Wi-Fi",
"backup_controller_page_backup": "Резервное копирование",
"backup_controller_page_backup_selected": "Выбрано: ",
"backup_controller_page_backup": "Загружено",
"backup_controller_page_backup_selected": "Выбраны: ",
"backup_controller_page_backup_sub": "Загруженные фото и видео",
"backup_controller_page_created": "Создано: {date}",
"backup_controller_page_desc_backup": "Включите резервное копирование в активном режиме, чтобы автоматически загружать новые объекты при открытии приложения.",
@@ -768,7 +768,7 @@
"default_locale": "Дата и время по умолчанию",
"default_locale_description": "Использовать формат даты и времени в соответствии с языковым стандартом вашего браузера",
"delete": "Удалить",
"delete_action_confirmation_message": "Вы действительно хотите удалить этот объект? Это действие переместит объект в корзину сервера и предложит удалить его локально.",
"delete_action_confirmation_message": "Вы действительно хотите удалить этот объект? Это действие переместит объект в корзину сервера и попробует удалить его локально.",
"delete_action_prompt": "Объекты удалены ({count} шт.)",
"delete_album": "Удалить альбом",
"delete_api_key_prompt": "Вы действительно хотите удалить этот API ключ?",
@@ -1041,7 +1041,7 @@
"external": "Внешний",
"external_libraries": "Внешние библиотеки",
"external_network": "Внешняя сеть",
"external_network_sheet_info": "Когда устройство не подключено к выбранной Wi-Fi сети, приложение будет пытаться подключиться к серверу по адресам ниже, сверху вниз, до успешного подключения",
"external_network_sheet_info": "Когда устройство не подключено к указанной Wi-Fi сети, приложение будет пытаться подключиться к серверу по адресам ниже, сверху вниз до успешного подключения",
"face_unassigned": "Не назначено",
"failed": "Ошибка",
"failed_to_authenticate": "Ошибка аутентификации",
@@ -1093,8 +1093,8 @@
"haptic_feedback_switch": "Включить тактильную отдачу",
"haptic_feedback_title": "Тактильная отдача",
"has_quota": "Квота",
"hash_asset": "Хешированный объект",
"hashed_assets": "Хешированные объекты",
"hash_asset": "Хеширование объектов",
"hashed_assets": "Хеши",
"hashing": "Хеширование",
"header_settings_add_header_tip": "Добавить заголовок",
"header_settings_field_validator_msg": "Значение не может быть пустым",
@@ -1112,14 +1112,14 @@
"home_page_add_to_album_conflicts": "Добавлено {added} медиа в альбом {album}. {failed} медиа уже в альбоме.",
"home_page_add_to_album_err_local": "Пока нельзя добавлять локальные объекты в альбомы, пропуск",
"home_page_add_to_album_success": "Добавлено {added} медиа в альбом {album}.",
"home_page_album_err_partner": "Пока нельзя добавить медиа партнера в альбом, пропуск",
"home_page_album_err_partner": "Невозможно добавить объекты партнёра в альбом, пропуск",
"home_page_archive_err_local": "Пока нельзя добавить локальные файлы в архив, пропуск",
"home_page_archive_err_partner": "Невозможно архивировать медиа партнера, пропуск",
"home_page_archive_err_partner": "Невозможно добавить объекты партнёра в архив, пропуск",
"home_page_building_timeline": "Построение хронологии",
"home_page_delete_err_partner": "Невозможно удалить медиа партнера, пропуск",
"home_page_delete_err_partner": "Невозможно удалить объекты партнёра, пропуск",
"home_page_delete_remote_err_local": "Невозможно удалить локальные файлы с сервера, пропуск",
"home_page_favorite_err_local": "Пока нельзя добавить в избранное локальные файлы, пропуск",
"home_page_favorite_err_partner": "Пока нельзя добавить в избранное медиа партнера, пропуск",
"home_page_favorite_err_partner": "Невозможно добавить объекты партнёра в избранное, пропуск",
"home_page_first_time_notice": "Перед началом использования приложения выберите альбом с объектами для резервного копирования, чтобы они отобразились на временной шкале",
"home_page_locked_error_local": "Невозможно переместить локальные объекты в личную папку, пропуск",
"home_page_locked_error_partner": "Невозможно переместить объекты партнёра в личную папку, пропуск",
@@ -1154,8 +1154,8 @@
"in_albums": "В {count, plural, one {# альбоме} other {# альбомах}}",
"in_archive": "В архиве",
"include_archived": "Отображать архив",
"include_shared_albums": "Включать общие альбомы",
"include_shared_partner_assets": "Включать общие ресурсы партнера",
"include_shared_albums": "Включать объекты общих альбомов",
"include_shared_partner_assets": "Включать объекты партнёров",
"individual_share": "Индивидуальная подборка",
"individual_shares": "Подборки",
"info": "Информация",
@@ -1219,7 +1219,7 @@
"local_asset_cast_failed": "Невозможна трансляция объектов, которые ещё не загружены на сервер",
"local_assets": "Объекты на устройстве",
"local_network": "Локальная сеть",
"local_network_sheet_info": "Приложение будет подключаться к серверу по этому адресу, когда устройство подключено к выбранной Wi-Fi сети",
"local_network_sheet_info": "Приложение будет подключаться к серверу по этому адресу, когда устройство подключено к указанной Wi-Fi сети",
"location_permission": "Доступ к местоположению",
"location_permission_content": "Чтобы использовать функцию автоматического переключения, Immich необходимо разрешение на точное определение местоположения, чтобы оно могло считывать название текущей Wi-Fi сети",
"location_picker_choose_on_map": "Выбрать на карте",
@@ -1367,7 +1367,7 @@
"no_duplicates_found": "Дубликатов не обнаружено.",
"no_exif_info_available": "Нет доступной информации exif",
"no_explore_results_message": "Загружайте больше фотографий, чтобы наслаждаться вашей коллекцией.",
"no_favorites_message": "Добавляйте в избранное, чтобы быстро найти свои лучшие фотографии и видео",
"no_favorites_message": "Добавляйте объекты в избранное, чтобы быстрее находить свои лучшие фото и видео",
"no_libraries_message": "Создайте внешнюю библиотеку для просмотра в Immich сторонних фотографий и видео",
"no_locked_photos_message": "Фото и видео, перемещенные в личную папку, скрыты и не отображаются при просмотре библиотеки.",
"no_name": "Нет имени",
@@ -1413,7 +1413,7 @@
"options": "Опции",
"or": "или",
"organize_into_albums": "Распределить по альбомам",
"organize_into_albums_description": "Добавить уже существующие фотографии в альбомы, используя текущие настройки синхронизации",
"organize_into_albums_description": "Добавить уже существующие объекты в альбомы, используя текущие настройки синхронизации",
"organize_your_library": "Приведите в порядок свою библиотеку",
"original": "оригинал",
"other": "Другое",
@@ -1422,18 +1422,18 @@
"other_variables": "Другие переменные",
"owned": "Мои",
"owner": "Владелец",
"partner": "Партнер",
"partner_can_access": "{partner} имеет доступ",
"partner_can_access_assets": "Все ваши фотографии и видеозаписи, кроме тех, которые находятся в Архиве и Корзине",
"partner_can_access_location": "Местоположение, где были сделаны ваши фотографии",
"partner_list_user_photos": "Фотографии пользователя {user}",
"partner": "Партнёр",
"partner_can_access": "Пользователю {partner} доступны",
"partner_can_access_assets": "Все ваши фото и видео, кроме тех, что находятся в архиве и корзине",
"partner_can_access_location": "Места, где были сделаны ваши фото и видео",
"partner_list_user_photos": "Фото и видео пользователя {user}",
"partner_list_view_all": "Посмотреть все",
"partner_page_empty_message": "У вашего партнёра еще нет доступа к вашим фото.",
"partner_page_empty_message": "Вы пока никому из партнёров не предоставили доступ к своим фото и видео.",
"partner_page_no_more_users": "Выбраны все доступные пользователи",
"partner_page_partner_add_failed": "Не удалось добавить партнёра",
"partner_page_select_partner": "Выбрать партнёра",
"partner_page_shared_to_title": "Поделиться с...",
"partner_page_stop_sharing_content": "Пользователь {partner} больше не сможет получить доступ к вашим фото.",
"partner_page_stop_sharing_content": "Пользователь {partner} больше не будет иметь доступ к вашим фото и видео.",
"partner_sharing": "Совместное использование",
"partners": "Партнёры",
"password": "Пароль",
@@ -1796,7 +1796,7 @@
"shared_by": "Поделился",
"shared_by_user": "Владелец: {user}",
"shared_by_you": "Вы поделились",
"shared_from_partner": "Фото и видео пользователя {partner}",
"shared_from_partner": "Пользователь {partner} предоставил вам доступ",
"shared_intent_upload_button_progress_text": "{current} / {total} Загружено",
"shared_link_app_bar_title": "Публичные ссылки",
"shared_link_clipboard_copied_massage": "Скопировано в буфер обмена",
@@ -1833,7 +1833,7 @@
"shared_links_description": "Делитесь фотографиями и видео по ссылке",
"shared_photos_and_videos_count": "{assetCount, plural, other {# фото и видео.}}",
"shared_with_me": "Доступные мне",
"shared_with_partner": "Совместно с {partner}",
"shared_with_partner": "Вы предоставили доступ пользователю {partner}",
"sharing": "Общие",
"sharing_enter_password": "Пожалуйста, введите пароль для просмотра этой страницы.",
"sharing_page_album": "Общие альбомы",
@@ -1851,7 +1851,7 @@
"show_gallery": "Показать галерею",
"show_hidden_people": "Показать скрытых людей",
"show_in_timeline": "Показать на временной шкале",
"show_in_timeline_setting_description": "Отображать фото и видео этого пользователя в своей ленте",
"show_in_timeline_setting_description": "Отображать фото и видео этого пользователя на своей временной шкале",
"show_keyboard_shortcuts": "Показать сочетания клавиш",
"show_metadata": "Показывать метаданные",
"show_or_hide_info": "Показать или скрыть информацию",
@@ -1897,9 +1897,9 @@
"status": "Состояние",
"stop_casting": "Остановить трансляцию",
"stop_motion_photo": "Покадровая анимация",
"stop_photo_sharing": "Закрыть доступ партнёра к вашим фото?",
"stop_photo_sharing": "Закрыть доступ партнёру?",
"stop_photo_sharing_description": "Пользователь {partner} больше не имеет доступа к вашим фотографиям.",
"stop_sharing_photos_with_user": "Прекратить делиться своими фотографиями с этим пользователем",
"stop_sharing_photos_with_user": "Прекратить делиться своими фото и видео с этим пользователем",
"storage": "Хранилище",
"storage_label": "Метка хранилища",
"storage_quota": "Квота хранилища",
@@ -1915,11 +1915,11 @@
"sync": "Синхр.",
"sync_albums": "Синхронизировать альбомы",
"sync_albums_manual_subtitle": "Синхронизировать все загруженные фото и видео в выбранные альбомы для резервного копирования",
"sync_local": "Синхронизировать локально",
"sync_local": "Локальная синхронизация",
"sync_remote": "Синхронизация с сервером",
"sync_status": "Статус синхронизации",
"sync_status_subtitle": "Просмотр и управление системой синхронизации",
"sync_upload_album_setting_subtitle": "Создавайте и загружайте свои фотографии и видео в выбранные альбомы на сервер Immich",
"sync_upload_album_setting_subtitle": "Создавать на сервере такие же альбомы, как выбранные на устройстве, и загружать в них фото и видео",
"tag": "Тег",
"tag_assets": "Добавить теги",
"tag_created": "Тег {tag} создан",

View File

@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "Mobilna aplikacija je zastarela. Posodobite na najnovejšo manjšo različico.",
"profile_drawer_client_server_up_to_date": "Odjemalec in strežnik sta posodobljena",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Način samo za branje je omogočen. Za izhod dvakrat tapnite ikono uporabniškega avatarja.",
"profile_drawer_readonly_mode": "Način samo za branje je omogočen. Za izhod dolgo pritisnite ikono uporabniškega avatarja.",
"profile_drawer_server_out_of_date_major": "Strežnik je zastarel. Posodobite na najnovejšo glavno različico.",
"profile_drawer_server_out_of_date_minor": "Strežnik je zastarel. Posodobite na najnovejšo manjšo različico.",
"profile_image_of_user": "Profilna slika uporabnika {user}",
@@ -1917,6 +1917,8 @@
"sync_albums_manual_subtitle": "Sinhronizirajte vse naložene videoposnetke in fotografije v izbrane varnostne albume",
"sync_local": "Sinhroniziraj lokalno",
"sync_remote": "Sinhroniziraj oddaljeno",
"sync_status": "Stanje sinhronizacije",
"sync_status_subtitle": "Ogled in upravljanje sistema sinhronizacije",
"sync_upload_album_setting_subtitle": "Ustvarite in naložite svoje fotografije in videoposnetke v izbrane albume na Immich",
"tag": "Oznaka",
"tag_assets": "Označi sredstva",
@@ -1976,6 +1978,7 @@
"trash_page_select_assets_btn": "Izberite sredstva",
"trash_page_title": "Smetnjak ({count})",
"trashed_items_will_be_permanently_deleted_after": "Elementi v smetnjaku bodo trajno izbrisani po {days, plural, one {# dnevu} two {# dnevih} few {# dnevih} other {# dneh}}.",
"troubleshoot": "Odpravljanje težav",
"type": "Vrsta",
"unable_to_change_pin_code": "PIN kode ni mogoče spremeniti",
"unable_to_setup_pin_code": "PIN kode ni mogoče nastaviti",

View File

@@ -4,6 +4,7 @@
"account_settings": "Podešavanja za Profil",
"acknowledge": "Potvrdi",
"action": "Postupak",
"action_common_update": "Ažuriraj",
"actions": "Postupci",
"active": "Aktivni",
"activity": "Aktivnost",
@@ -13,6 +14,7 @@
"add_a_location": "Dodaj Lokaciju",
"add_a_name": "Dodaj ime",
"add_a_title": "Dodaj naslov",
"add_birthday": "Dodaj rođendan",
"add_endpoint": "Dodajte krajnju tačku",
"add_exclusion_pattern": "Dodajte obrazac izuzimanja",
"add_import_path": "Dodaj putanju za preuzimanje",
@@ -21,10 +23,14 @@
"add_partner": "Dodaj partner",
"add_path": "Dodaj putanju",
"add_photos": "Dodaj fotografije",
"add_tag": "Dodaj oznaku",
"add_to": "Dodaj u…",
"add_to_album": "Dodaj u album",
"add_to_album_bottom_sheet_added": "Dodato u {album}",
"add_to_album_bottom_sheet_already_exists": "Već u {album}",
"add_to_album_toggle": "Uključi/isključi izbor za {album}",
"add_to_albums": "Dodaj u albume",
"add_to_albums_count": "Dodaj u albume ({count})",
"add_to_shared_album": "Dodaj u deljen album",
"add_url": "Dodaj URL",
"added_to_archive": "Dodato u arhivu",
@@ -32,6 +38,7 @@
"added_to_favorites_count": "Dodato {count, number} u favorite",
"admin": {
"add_exclusion_pattern_description": "Dodajte obrasce isključenja. Korištenje *, ** i ? je podržano. Da biste ignorisali sve datoteke u bilo kom direktorijumu pod nazivom „Rav“, koristite „**/Rav/**“. Da biste ignorisali sve datoteke koje se završavaju na „.tif“, koristite „**/*.tif“. Da biste ignorisali apsolutnu putanju, koristite „/path/to/ignore/**“.",
"admin_user": "Administrator",
"asset_offline_description": "Ovo eksterno bibliotečko sredstvo se više ne nalazi na disku i premešteno je u smeće. Ako je datoteka premeštena unutar biblioteke, proverite svoju vremensku liniju za novo odgovarajuće sredstvo. Da biste vratili ovo sredstvo, uverite se da Immich može da pristupi dole navedenoj putanji datoteke i skenirajte biblioteku.",
"authentication_settings": "Podešavanja za autentifikaciju",
"authentication_settings_description": "Upravljajte lozinkom, OAuth-om i drugim podešavanjima autentifikacije",
@@ -41,8 +48,15 @@
"backup_database": "Kreirajte rezervnu kopiju baze podataka",
"backup_database_enable_description": "Omogući dampove baze podataka",
"backup_keep_last_amount": "Količina prethodnih dampova koje treba zadržati",
"backup_onboarding_1_description": "kopija na oblaku ili na drugoj fizičkoj lokaciji.",
"backup_onboarding_2_description": "lokalne kopije na različitim uređajima. Ovo uključuje glavne datoteke i rezervnu kopiju tih datoteka lokalno.",
"backup_onboarding_3_description": "ukupno kopija vaših podataka, uklučujući originalne datoteke. Ovo uključuje 1 udaljenu kopiju i 2 lokalne kopije.",
"backup_onboarding_description": "<backblaze-link>3-2-1 strategija rezervnih kopija</backblaze-link> je preporučena da zaštiti vaše podatke. Trebali biste čuvati kopije vaših otpremljenih slika/videa kao i Immich bazu podataka za sveobuhvatno rešenje za rezervne kopije.",
"backup_onboarding_footer": "Za više informacija o pravljenju rezervne kopije Immich-a, molimo vas pogledajte <link>dokumentaciju</link>.",
"backup_onboarding_parts_title": "3-2-1 rezervna kopija uključuje:",
"backup_onboarding_title": "Rezervne kopije",
"backup_settings": "Podešavanja dampa baze podataka",
"backup_settings_description": "Upravljajte podešavanjima dampa baze podataka. Napomena: Ovi poslovi se ne prate i nećete biti obavešteni o neuspehu.",
"backup_settings_description": "Upravljajte podešavanjima dampa baze podataka.",
"cleared_jobs": "Očišćeni poslovi za: {job}",
"config_set_by_file": "Konfiguraciju trenutno postavlja konfiguracioni fajl",
"confirm_delete_library": "Da li stvarno želite da izbrišete biblioteku {library} ?",
@@ -163,12 +177,23 @@
"metadata_settings_description": "Upravljajte podešavanjima metapodataka",
"migration_job": "Migracije",
"migration_job_description": "Prenesite sličice datoteka i lica u najnoviju strukturu direktorijuma",
"nightly_tasks_cluster_faces_setting_description": "Pokreni prepoznavanje lica na novodetektovanim licima",
"nightly_tasks_cluster_new_faces_setting": "Združi nova lica",
"nightly_tasks_database_cleanup_setting": "Zadaci čiščenja baze podataka",
"nightly_tasks_database_cleanup_setting_description": "Očisti stare, istekle podatke iz baze podataka",
"nightly_tasks_generate_memories_setting": "Generiši sjećanja",
"nightly_tasks_generate_memories_setting_description": "Kreiraj nova sjećanja",
"nightly_tasks_missing_thumbnails_setting": "Generiši nedostajuće sličice",
"nightly_tasks_missing_thumbnails_setting_description": "Dodajte elemente bez sličica u red za generisanje sličica",
"nightly_tasks_settings": "Podešavanja noćnih zadataka",
"nightly_tasks_settings_description": "Upravljaj noćnim zadacima",
"nightly_tasks_sync_quota_usage_setting_description": "Ažurirajte kvotu memorijskog prostora korisnika na osnovu trenutne upotrebe",
"no_paths_added": "Nema dodatih putanja",
"no_pattern_added": "Nije dodat obrazac",
"note_apply_storage_label_previous_assets": "Napomena: Da biste primenili oznaku za skladištenje na prethodno otpremljena sredstva, pokrenite",
"note_cannot_be_changed_later": "NAPOMENA: Ovo se kasnije ne može promeniti!",
"notification_email_from_address": "Sa adrese",
"notification_email_from_address_description": "Adresa e-pošte pošiljaoca, na primer: \"Immich foto server <noreply@example.com>\"",
"notification_email_from_address_description": "Adresa e-pošte pošiljaoca, na primer: \"Immich foto server <noreply@example.com>\". Pobrinite se da koristite adresu sa koje vam je dozovljeno slati e-poštu.",
"notification_email_host_description": "Host servera e-pošte (npr. smtp.immich.app)",
"notification_email_ignore_certificate_errors": "Zanemarite greške sertifikata",
"notification_email_ignore_certificate_errors_description": "Ignorišite greške u validaciji TLS sertifikata (ne preporučuje se)",
@@ -201,7 +226,7 @@
"oauth_storage_quota_claim": "Zahtev za kvotu skladištenja",
"oauth_storage_quota_claim_description": "Automatski podesite kvotu memorijskog prostora korisnika na vrednost ovog zahteva.",
"oauth_storage_quota_default": "Podrazumevana kvota za skladištenje (GiB)",
"oauth_storage_quota_default_description": "Kvota u GiB koja se koristi kada nema potraživanja (unesite 0 za neograničenu kvotu).",
"oauth_storage_quota_default_description": "Kvota u GiB koja se koristi kada nema potraživanja.",
"oauth_timeout": "Vremensko ograničenje zahteva",
"oauth_timeout_description": "Vremensko ograničenje za zahteve u milisekundama",
"password_enable_description": "Prijavite se pomoću e-pošte i lozinke",
@@ -508,7 +533,7 @@
"backup_controller_page_background_turn_off": "Isključi pozadinski servis",
"backup_controller_page_background_turn_on": "Uključi pozadinski servis",
"backup_controller_page_background_wifi": "Samo na Wi-Fi",
"backup_controller_page_backup": "Napravi rezervnu kopiju",
"backup_controller_page_backup": "Rezervne kopije",
"backup_controller_page_backup_selected": "Odabrano: ",
"backup_controller_page_backup_sub": "Završeno pravljenje rezervne kopije fotografija i videa",
"backup_controller_page_created": "Napravljeno:{date}",
@@ -519,8 +544,8 @@
"backup_controller_page_id": "ID:{id}",
"backup_controller_page_info": "Informacije",
"backup_controller_page_none_selected": "Ništa odabrano",
"backup_controller_page_remainder": "Podsetnik",
"backup_controller_page_remainder_sub": "Ostalo fotografija i videa da se otpremi od selekcije",
"backup_controller_page_remainder": "Ostatak",
"backup_controller_page_remainder_sub": "Ostale fotografije i video snimci za otpremanje od selekcije",
"backup_controller_page_server_storage": "Prostor na serveru",
"backup_controller_page_start_backup": "Pokreni pravljenje rezervne kopije",
"backup_controller_page_status_off": "Automatsko pravljenje rezervnih kopija u prvom planu je isključeno",

View File

@@ -1515,7 +1515,7 @@
"profile_drawer_client_out_of_date_minor": "Mobilappen är föråldrad. Uppdatera till senaste versionen.",
"profile_drawer_client_server_up_to_date": "Klient och server är uppdaterade",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Skrivskyddat läge aktiverat. Dubbeltryck på användaravatarikonen för att avsluta",
"profile_drawer_readonly_mode": "Skrivskyddat läge aktiverat. Håll in användaravatarikonen för att avsluta",
"profile_drawer_server_out_of_date_major": "Servern har en föråldrad mjukvara. Uppdatera till senaste versionen.",
"profile_drawer_server_out_of_date_minor": "Servern har en föråldrad mjukvara. Uppdatera till senaste versionen.",
"profile_image_of_user": "{user} profilbild",
@@ -1917,6 +1917,8 @@
"sync_albums_manual_subtitle": "Synka alla uppladdade videor och foton till valda backup-album",
"sync_local": "Synkronisera lokalt",
"sync_remote": "Synkronisera fjärrserver",
"sync_status": "Synk Status",
"sync_status_subtitle": "Visa och hantera synkroniseringssystemet",
"sync_upload_album_setting_subtitle": "Skapa och ladda upp dina foton och videor till de valda albumen på Immich",
"tag": "Tagg",
"tag_assets": "Tagga tillgångar",
@@ -1976,6 +1978,7 @@
"trash_page_select_assets_btn": "Välj objekt",
"trash_page_title": "Papperskorg ({count})",
"trashed_items_will_be_permanently_deleted_after": "Objekt i papperskorgen raderas permanent efter {days, plural, one {# dag} other {# dagar}}.",
"troubleshoot": "Felsök",
"type": "Typ",
"unable_to_change_pin_code": "Kunde inte ändra pinkod",
"unable_to_setup_pin_code": "Kunde inte konfigurera pinkod",

File diff suppressed because it is too large Load Diff

View File

@@ -1640,7 +1640,7 @@
"restore_user": "Відновити користувача",
"restored_asset": "Відновлений ресурс",
"resume": "Продовжити",
"resume_paused_jobs": "Резюме {count, plural, one {# призупинене завдання} other {# призупинені завдання}}",
"resume_paused_jobs": "Відновити {count, plural, one {# призупинене завдання} other {# призупинені завдання}}",
"retry_upload": "Повторити завантаження",
"review_duplicates": "Переглянути дублікати",
"review_large_files": "Перегляд великих файлів",

View File

@@ -1510,7 +1510,7 @@
"profile_drawer_client_out_of_date_minor": "客戶端有小版本升級,請盡快升級至最新版。",
"profile_drawer_client_server_up_to_date": "客戶端和服務端都是最新的",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "唯讀模式已開啟。請連點兩下使用者頭像圖示以退出。",
"profile_drawer_readonly_mode": "唯讀模式已開啟。請長按使用者頭像圖示以退出。",
"profile_drawer_server_out_of_date_major": "服務端有大版本升級,請盡快升級至最新版。",
"profile_drawer_server_out_of_date_minor": "服務端有小版本升級,請盡快升級至最新版。",
"profile_image_of_user": "{user} 的個人資料圖片",
@@ -1549,6 +1549,7 @@
"purchase_server_description_2": "擁護者狀態",
"purchase_server_title": "伺服器",
"purchase_settings_server_activated": "伺服器產品金鑰是由管理者管理的",
"query_asset_id": "査詢資產ID",
"queue_status": "處理中 {count}/{total}",
"rating": "評星",
"rating_clear": "清除評等",
@@ -1634,6 +1635,7 @@
"restore_user": "還原使用者",
"restored_asset": "已還原檔案",
"resume": "繼續",
"resume_paused_jobs": "恢復 {count, plural, one {# 暫停的任務} other {# 暫停的任務}}",
"retry_upload": "重新上傳",
"review_duplicates": "檢視重複項目",
"review_large_files": "檢視大型文件",
@@ -1910,6 +1912,8 @@
"sync_albums_manual_subtitle": "將所有上傳的短片和照片同步到選定的備份相簿",
"sync_local": "同步本機",
"sync_remote": "同步遠端",
"sync_status": "同步状态",
"sync_status_subtitle": "查看和管理同步系統",
"sync_upload_album_setting_subtitle": "新增照片和短片並上傳到 Immich 上的選定相簿中",
"tag": "標籤",
"tag_assets": "標記檔案",
@@ -1947,7 +1951,9 @@
"to_change_password": "變更密碼",
"to_favorite": "收藏",
"to_login": "登入",
"to_multi_select": "進行多選",
"to_parent": "到上一級",
"to_select": "选择",
"to_trash": "垃圾桶",
"toggle_settings": "切換設定",
"total": "統計",
@@ -1967,6 +1973,7 @@
"trash_page_select_assets_btn": "選擇項目",
"trash_page_title": "垃圾桶 ({count})",
"trashed_items_will_be_permanently_deleted_after": "垃圾桶中的項目會在 {days, plural, other {# 天}}後永久刪除。",
"troubleshoot": "疑难解答",
"type": "類型",
"unable_to_change_pin_code": "無法變更 PIN 碼",
"unable_to_setup_pin_code": "無法設定 PIN 碼",
@@ -1997,6 +2004,7 @@
"unstacked_assets_count": "已解除堆疊 {count, plural, other {# 個檔案}}",
"untagged": "無標籤",
"up_next": "下一個",
"update_location_action_prompt": "使用以下命令更新{count}個所選資產的位置:",
"updated_at": "更新於",
"updated_password": "已更新密碼",
"upload": "上傳",
@@ -2063,6 +2071,7 @@
"view_next_asset": "查看下一項",
"view_previous_asset": "查看上一項",
"view_qr_code": "查看 QR code",
"view_similar_photos": "查看相似照片",
"view_stack": "查看堆疊",
"view_user": "顯示使用者",
"viewer_remove_from_stack": "從堆疊中移除",

View File

@@ -26,8 +26,8 @@
"add_tag": "添加标签",
"add_to": "添加到…",
"add_to_album": "添加到相册",
"add_to_album_bottom_sheet_added": "添加到 {album}",
"add_to_album_bottom_sheet_already_exists": "已在 {album} 中",
"add_to_album_bottom_sheet_added": "添加到相册 “{album}",
"add_to_album_bottom_sheet_already_exists": "已在相册“ {album} 中",
"add_to_album_toggle": "选择相册 {album}",
"add_to_albums": "添加到相册",
"add_to_albums_count": "添加到相册({count}个)",
@@ -100,7 +100,7 @@
"image_thumbnail_description": "剥离元数据的小缩略图,用于浏览主时间线等照片组",
"image_thumbnail_quality_description": "缩略图质量从 1 到 100。越高越好但会产生更大的文件并且会降低系统的响应能力。",
"image_thumbnail_title": "缩略图设置",
"job_concurrency": "{job}并发",
"job_concurrency": "{job}任务并发",
"job_created": "任务已创建",
"job_not_concurrency_safe": "此任务并发并不安全。",
"job_settings": "任务设置",
@@ -121,13 +121,13 @@
"library_watching_settings": "监控图库(实验性)",
"library_watching_settings_description": "自动监控文件变化",
"logging_enable_description": "启用日志记录",
"logging_level_description": "启用的日志级别。",
"logging_level_description": "启用时,要使用的日志级别。",
"logging_settings": "日志",
"machine_learning_clip_model": "CLIP 模型",
"machine_learning_clip_model_description": "请于 <link>此处</link>查看支持的 CLIP 模型名称。注意,更换模型后需要对所有图片重新运行“智能搜索”任务。",
"machine_learning_duplicate_detection": "重复项检测",
"machine_learning_duplicate_detection_enabled": "启用重复检测",
"machine_learning_duplicate_detection_enabled_description": "如果禁用此功能,完全相同的项目仍将被去重。",
"machine_learning_duplicate_detection_enabled_description": "如果禁用,完全相同的项目仍将被去重。",
"machine_learning_duplicate_detection_setting_description": "使用 CLIP 向量匹配(关键词相似度)来查找可能的重复项",
"machine_learning_enabled": "启用机器学习",
"machine_learning_enabled_description": "如果禁用,无论以下如何设置,所有机器学习功能将被禁用。",
@@ -158,7 +158,7 @@
"map_enable_description": "启用地图功能",
"map_gps_settings": "地图与 GPS 设置",
"map_gps_settings_description": "管理地图与 GPS反向地理编码设置",
"map_implications": "地图功能依赖于外部地形贴图服务tiles.immich.cloud",
"map_implications": "地图功能依赖于外部地图瓦片服务tiles.immich.cloud",
"map_light_style": "浅色模式",
"map_manage_reverse_geocoding_settings": "管理<link>反向地理编码</link>设置",
"map_reverse_geocoding": "反向地理编码",
@@ -220,7 +220,7 @@
"oauth_enable_description": "使用 OAuth 登录",
"oauth_mobile_redirect_uri": "移动端重定向 URI",
"oauth_mobile_redirect_uri_override": "移动端重定向 URI 覆盖",
"oauth_mobile_redirect_uri_override_description": "当 OAuth 提供商不允许使用移动 URI 时启用,如“''{callback}''”",
"oauth_mobile_redirect_uri_override_description": "当 OAuth 提供商不允许使用移动 URI 时启用,如“{callback}”",
"oauth_role_claim": "角色声明",
"oauth_role_claim_description": "根据此声明的存在自动授予管理员访问权限。声明可以是“user”用户或“admin”管理员。",
"oauth_settings": "OAuth",
@@ -364,7 +364,7 @@
"user_cleanup_job": "清理用户",
"user_delete_delay": "<b>{user}</b>的账户及项目将在{delay, plural, one {#天} other {#天}}后自动永久删除。",
"user_delete_delay_settings": "延期删除",
"user_delete_delay_settings_description": "永久删除账户及其所有项目之前所保留的天数。用户删除作业会在午夜检查是否有用户可以删除。对该设置的更改将在下次执行时生效。",
"user_delete_delay_settings_description": "删除后永久删除用户帐户和资产的天数。用户删除作业会在午夜检查是否有用户可以删除。对该设置的更改将在下次执行时生效。",
"user_delete_immediately": "<b>{user}</b>的账户及项目将<b>立即</b>永久删除。",
"user_delete_immediately_checkbox": "立即删除检索到的用户及项目",
"user_details": "用户详情",
@@ -1640,7 +1640,7 @@
"restore_user": "恢复用户",
"restored_asset": "已恢复项目",
"resume": "继续",
"resume_paused_jobs": "继续 {count, plural, one {# 已暂停的作业} other {# 已暂停的作业}}",
"resume_paused_jobs": "继续 {count, plural, one {# 已暂停的任务} other {# 已暂停的任务}}",
"retry_upload": "重新上传",
"review_duplicates": "检查重复项",
"review_large_files": "查看大文件",
@@ -1929,7 +1929,7 @@
"tag_updated": "已更新标签:{tag}",
"tagged_assets": "{count, plural, one {# 个项目} other {# 个项目}}被加上标签",
"tags": "标签",
"tap_to_run_job": "点击运行作业",
"tap_to_run_job": "点击运行任务",
"template": "模版",
"theme": "主题",
"theme_selection": "主题选项",

View File

@@ -22,7 +22,7 @@ FROM builder-cpu AS builder-rknn
# Warning: 25GiB+ disk space required to pull this image
# TODO: find a way to reduce the image size
FROM rocm/dev-ubuntu-22.04:6.3.4-complete@sha256:1f7e92ca7e3a3785680473329ed1091fc99db3e90fcb3a1688f2933e870ed76b AS builder-rocm
FROM rocm/dev-ubuntu-22.04:6.4.3-complete@sha256:1f7e92ca7e3a3785680473329ed1091fc99db3e90fcb3a1688f2933e870ed76b AS builder-rocm
# renovate: datasource=github-releases depName=Microsoft/onnxruntime
ARG ONNXRUNTIME_VERSION="v1.20.1"
@@ -99,7 +99,7 @@ COPY --from=builder-cuda /usr/local/bin/python3 /usr/local/bin/python3
COPY --from=builder-cuda /usr/local/lib/python3.11 /usr/local/lib/python3.11
COPY --from=builder-cuda /usr/local/lib/libpython3.11.so /usr/local/lib/libpython3.11.so
FROM rocm/dev-ubuntu-22.04:6.3.4-complete@sha256:1f7e92ca7e3a3785680473329ed1091fc99db3e90fcb3a1688f2933e870ed76b AS prod-rocm
FROM rocm/dev-ubuntu-22.04:6.4.3-complete@sha256:1f7e92ca7e3a3785680473329ed1091fc99db3e90fcb3a1688f2933e870ed76b AS prod-rocm
FROM prod-cpu AS prod-armnn

View File

@@ -1,34 +0,0 @@
[tools.dart]
version = "3.8.2"
backend = "asdf:dart"
[tools.flutter]
version = "3.32.8-stable"
backend = "asdf:flutter"
[tools."github:CQLabs/homebrew-dcm"]
version = "1.31.4"
backend = "github:CQLabs/homebrew-dcm"
[tools."github:CQLabs/homebrew-dcm".platforms.linux-x64]
checksum = "blake3:e9df5b765df327e1248fccf2c6165a89d632a065667f99c01765bf3047b94955"
size = 8821083
url = "https://github.com/CQLabs/homebrew-dcm/releases/download/1.31.4/dcm-linux-x64-release.zip"
[tools.node]
version = "22.18.0"
backend = "core:node"
[tools.node.platforms.linux-x64]
checksum = "sha256:a2e703725d8683be86bb5da967bf8272f4518bdaf10f21389e2b2c9eaeae8c8a"
size = 54824343
url = "https://nodejs.org/dist/v22.18.0/node-v22.18.0-linux-x64.tar.gz"
[tools.pnpm]
version = "10.14.0"
backend = "aqua:pnpm/pnpm"
[tools.pnpm.platforms.linux-x64]
checksum = "blake3:13dfa46b7173d3cad3bad60a756a492ecf0bce48b23eb9f793e7ccec5a09b46d"
size = 66231525
url = "https://github.com/pnpm/pnpm/releases/download/v10.14.0/pnpm-linux-x64"

View File

@@ -1,6 +1,6 @@
[tools]
node = "22.19.0"
flutter = "3.32.8"
flutter = "3.35.4"
pnpm = "10.14.0"
dart = "3.8.2"
@@ -11,7 +11,6 @@ postinstall = "chmod +x $MISE_TOOL_INSTALL_PATH/dcm"
[settings]
experimental = true
lockfile = true
pin = true
# .github
@@ -300,7 +299,7 @@ run = "tsc --noEmit"
depends = "web:svelte-kit-sync"
env._.path = "web/node_modules/.bin"
dir = "web"
run = "svelte-check --no-tsconfig --fail-on-warnings --compiler-warnings 'reactive_declaration_non_reactive_property:ignore' --ignore src/lib/components/photos-page/asset-grid.svelte"
run = "svelte-check --no-tsconfig --fail-on-warnings"
[tasks."web:checklist"]
run = [

View File

@@ -1,3 +1,3 @@
{
"flutter": "3.32.8"
"flutter": "3.35.4"
}

View File

@@ -1,8 +1,8 @@
{
"dart.flutterSdkPath": ".fvm/versions/3.32.8",
"dart.flutterSdkPath": ".fvm/versions/3.35.4",
"dart.lineLength": 120,
"[dart]": {
"editor.rulers": [120],
"editor.rulers": [120]
},
"search.exclude": {
"**/.fvm": true

View File

@@ -43,8 +43,9 @@ analyzer:
- lib/**/*.g.dart
- lib/**/*.drift.dart
plugins:
- custom_lint
# TODO: Re-enable after upgrading custom_lint
# plugins:
# - custom_lint
custom_lint:
debug: true
@@ -134,6 +135,13 @@ custom_lint:
dart_code_metrics:
rules:
- banned-usage:
entries:
- name: debugPrint
description: Use dPrint instead of debugPrint for proper tree-shaking in release builds.
exclude-paths:
- 'lib/utils/debug_print.dart'
severity: perf
# All rules from "recommended" preset
# Show potential errors
# - avoid-cascade-after-if-null

View File

@@ -3,6 +3,7 @@ package app.alextran.immich
import android.app.Application
import androidx.work.Configuration
import androidx.work.WorkManager
import app.alextran.immich.background.BackgroundWorkerApiImpl
class ImmichApp : Application() {
override fun onCreate() {
@@ -14,6 +15,8 @@ class ImmichApp : Application() {
// Thus, the BackupWorker is not started. If the system kills the process after each initialization
// (because of low memory etc.), the backup is never performed.
// As a workaround, we also run a backup check when initializing the application
ContentObserverWorker.startBackupWorker(context = this, delayMilliseconds = 0)
BackgroundWorkerApiImpl.enqueueBackgroundWorker(this)
}
}

View File

@@ -3,6 +3,7 @@ package app.alextran.immich
import android.content.Context
import android.os.Build
import android.os.ext.SdkExtensions
import app.alextran.immich.background.BackgroundEngineLock
import app.alextran.immich.background.BackgroundWorkerApiImpl
import app.alextran.immich.background.BackgroundWorkerFgHostApi
import app.alextran.immich.connectivity.ConnectivityApi
@@ -25,6 +26,7 @@ class MainActivity : FlutterFragmentActivity() {
fun registerPlugins(ctx: Context, flutterEngine: FlutterEngine) {
flutterEngine.plugins.add(BackgroundServicePlugin())
flutterEngine.plugins.add(HttpSSLOptionsPlugin())
flutterEngine.plugins.add(BackgroundEngineLock())
val messenger = flutterEngine.dartExecutor.binaryMessenger
val nativeSyncApiImpl =

View File

@@ -0,0 +1,33 @@
package app.alextran.immich.background
import android.util.Log
import androidx.work.WorkManager
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.embedding.engine.plugins.FlutterPlugin
import java.util.concurrent.atomic.AtomicInteger
private const val TAG = "BackgroundEngineLock"
class BackgroundEngineLock : FlutterPlugin {
companion object {
const val ENGINE_CACHE_KEY = "immich::background_worker::engine"
var engineCount = AtomicInteger(0)
}
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
// work manager task is running while the main app is opened, cancel the worker
if (engineCount.incrementAndGet() > 1 && FlutterEngineCache.getInstance()
.get(ENGINE_CACHE_KEY) != null
) {
WorkManager.getInstance(binding.applicationContext)
.cancelUniqueWork(BackgroundWorkerApiImpl.BACKGROUND_WORKER_NAME)
FlutterEngineCache.getInstance().remove(ENGINE_CACHE_KEY)
}
Log.i(TAG, "Flutter engine attached. Attached Engines count: $engineCount")
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
engineCount.decrementAndGet()
Log.i(TAG, "Flutter engine detached. Attached Engines count: $engineCount")
}
}

View File

@@ -37,6 +37,36 @@ private object BackgroundWorkerPigeonUtils {
)
}
}
fun deepEquals(a: Any?, b: Any?): Boolean {
if (a is ByteArray && b is ByteArray) {
return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
return a.contentEquals(b)
}
if (a is Array<*> && b is Array<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals(a[it], b[it]) }
}
if (a is List<*> && b is List<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals(a[it], b[it]) }
}
if (a is Map<*, *> && b is Map<*, *>) {
return a.size == b.size && a.all {
(b as Map<Any?, Any?>).containsKey(it.key) &&
deepEquals(it.value, b[it.key])
}
}
return a == b
}
}
/**
@@ -50,18 +80,63 @@ class FlutterError (
override val message: String? = null,
val details: Any? = null
) : Throwable()
/** Generated class from Pigeon that represents data sent in messages. */
data class BackgroundWorkerSettings (
val requiresCharging: Boolean,
val minimumDelaySeconds: Long
)
{
companion object {
fun fromList(pigeonVar_list: List<Any?>): BackgroundWorkerSettings {
val requiresCharging = pigeonVar_list[0] as Boolean
val minimumDelaySeconds = pigeonVar_list[1] as Long
return BackgroundWorkerSettings(requiresCharging, minimumDelaySeconds)
}
}
fun toList(): List<Any?> {
return listOf(
requiresCharging,
minimumDelaySeconds,
)
}
override fun equals(other: Any?): Boolean {
if (other !is BackgroundWorkerSettings) {
return false
}
if (this === other) {
return true
}
return BackgroundWorkerPigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
}
private open class BackgroundWorkerPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return super.readValueOfType(type, buffer)
return when (type) {
129.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
BackgroundWorkerSettings.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
}
}
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
super.writeValue(stream, value)
when (value) {
is BackgroundWorkerSettings -> {
stream.write(129)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface BackgroundWorkerFgHostApi {
fun enable()
fun configure(settings: BackgroundWorkerSettings)
fun disable()
companion object {
@@ -89,6 +164,24 @@ interface BackgroundWorkerFgHostApi {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.configure$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val settingsArg = args[0] as BackgroundWorkerSettings
val wrapped: List<Any?> = try {
api.configure(settingsArg)
listOf(null)
} catch (exception: Throwable) {
BackgroundWorkerPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.disable$separatedMessageChannelSuffix", codec)
if (api != null) {

View File

@@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.SettableFuture
import io.flutter.FlutterInjector
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.embedding.engine.loader.FlutterLoader
import java.util.concurrent.TimeUnit
@@ -54,12 +55,6 @@ class BackgroundWorker(context: Context, params: WorkerParameters) :
private var foregroundFuture: ListenableFuture<Void>? = null
init {
if (!loader.initialized()) {
loader.startInitialization(ctx)
}
}
companion object {
private const val NOTIFICATION_CHANNEL_ID = "immich::background_worker::notif"
private const val NOTIFICATION_ID = 100
@@ -68,6 +63,10 @@ class BackgroundWorker(context: Context, params: WorkerParameters) :
override fun startWork(): ListenableFuture<Result> {
Log.i(TAG, "Starting background upload worker")
if (!loader.initialized()) {
loader.startInitialization(ctx)
}
val notificationChannel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID,
@@ -77,6 +76,9 @@ class BackgroundWorker(context: Context, params: WorkerParameters) :
loader.ensureInitializationCompleteAsync(ctx, null, Handler(Looper.getMainLooper())) {
engine = FlutterEngine(ctx)
FlutterEngineCache.getInstance().remove(BackgroundEngineLock.ENGINE_CACHE_KEY);
FlutterEngineCache.getInstance()
.put(BackgroundEngineLock.ENGINE_CACHE_KEY, engine!!)
// Register custom plugins
MainActivity.registerPlugins(ctx, engine!!)
@@ -190,6 +192,7 @@ class BackgroundWorker(context: Context, params: WorkerParameters) :
isComplete = true
engine?.destroy()
engine = null
FlutterEngineCache.getInstance().remove(BackgroundEngineLock.ENGINE_CACHE_KEY);
flutterApi = null
notificationManager.cancel(NOTIFICATION_ID)
waitForForegroundPromotion()

View File

@@ -1,6 +1,7 @@
package app.alextran.immich.background
import android.content.Context
import android.content.SharedPreferences
import android.provider.MediaStore
import android.util.Log
import androidx.work.BackoffPolicy
@@ -10,7 +11,7 @@ import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import java.util.concurrent.TimeUnit
private const val TAG = "BackgroundUploadImpl"
private const val TAG = "BackgroundWorkerApiImpl"
class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
private val ctx: Context = context.applicationContext
@@ -19,25 +20,34 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
enqueueMediaObserver(ctx)
}
override fun configure(settings: BackgroundWorkerSettings) {
BackgroundWorkerPreferences(ctx).updateSettings(settings)
enqueueMediaObserver(ctx)
}
override fun disable() {
WorkManager.getInstance(ctx).cancelUniqueWork(OBSERVER_WORKER_NAME)
WorkManager.getInstance(ctx).cancelUniqueWork(BACKGROUND_WORKER_NAME)
WorkManager.getInstance(ctx).apply {
cancelUniqueWork(OBSERVER_WORKER_NAME)
cancelUniqueWork(BACKGROUND_WORKER_NAME)
}
Log.i(TAG, "Cancelled background upload tasks")
}
companion object {
private const val BACKGROUND_WORKER_NAME = "immich/BackgroundWorkerV1"
const val BACKGROUND_WORKER_NAME = "immich/BackgroundWorkerV1"
private const val OBSERVER_WORKER_NAME = "immich/MediaObserverV1"
fun enqueueMediaObserver(ctx: Context) {
val constraints = Constraints.Builder()
.addContentUriTrigger(MediaStore.Images.Media.INTERNAL_CONTENT_URI, true)
.addContentUriTrigger(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true)
.addContentUriTrigger(MediaStore.Video.Media.INTERNAL_CONTENT_URI, true)
.addContentUriTrigger(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true)
.setTriggerContentUpdateDelay(30, TimeUnit.SECONDS)
.setTriggerContentMaxDelay(3, TimeUnit.MINUTES)
.build()
val settings = BackgroundWorkerPreferences(ctx).getSettings()
val constraints = Constraints.Builder().apply {
addContentUriTrigger(MediaStore.Images.Media.INTERNAL_CONTENT_URI, true)
addContentUriTrigger(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true)
addContentUriTrigger(MediaStore.Video.Media.INTERNAL_CONTENT_URI, true)
addContentUriTrigger(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true)
setTriggerContentUpdateDelay(settings.minimumDelaySeconds, TimeUnit.SECONDS)
setTriggerContentMaxDelay(settings.minimumDelaySeconds * 10, TimeUnit.MINUTES)
setRequiresCharging(settings.requiresCharging)
}.build()
val work = OneTimeWorkRequest.Builder(MediaObserver::class.java)
.setConstraints(constraints)
@@ -45,7 +55,10 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
WorkManager.getInstance(ctx)
.enqueueUniqueWork(OBSERVER_WORKER_NAME, ExistingWorkPolicy.REPLACE, work)
Log.i(TAG, "Enqueued media observer worker with name: $OBSERVER_WORKER_NAME")
Log.i(
TAG,
"Enqueued media observer worker with name: $OBSERVER_WORKER_NAME and settings: $settings"
)
}
fun enqueueBackgroundWorker(ctx: Context) {
@@ -56,9 +69,39 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
.build()
WorkManager.getInstance(ctx)
.enqueueUniqueWork(BACKGROUND_WORKER_NAME, ExistingWorkPolicy.REPLACE, work)
.enqueueUniqueWork(BACKGROUND_WORKER_NAME, ExistingWorkPolicy.KEEP, work)
Log.i(TAG, "Enqueued background worker with name: $BACKGROUND_WORKER_NAME")
}
}
}
private class BackgroundWorkerPreferences(private val ctx: Context) {
companion object {
private const val SHARED_PREF_NAME = "Immich::BackgroundWorker"
private const val SHARED_PREF_MIN_DELAY_KEY = "BackgroundWorker::minDelaySeconds"
private const val SHARED_PREF_REQUIRE_CHARGING_KEY = "BackgroundWorker::requireCharging"
private const val DEFAULT_MIN_DELAY_SECONDS = 30L
private const val DEFAULT_REQUIRE_CHARGING = false
}
private val sp: SharedPreferences by lazy {
ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
}
fun updateSettings(settings: BackgroundWorkerSettings) {
sp.edit().apply {
putLong(SHARED_PREF_MIN_DELAY_KEY, settings.minimumDelaySeconds)
putBoolean(SHARED_PREF_REQUIRE_CHARGING_KEY, settings.requiresCharging)
apply()
}
}
fun getSettings(): BackgroundWorkerSettings {
return BackgroundWorkerSettings(
minimumDelaySeconds = sp.getLong(SHARED_PREF_MIN_DELAY_KEY, DEFAULT_MIN_DELAY_SECONDS),
requiresCharging = sp.getBoolean(SHARED_PREF_REQUIRE_CHARGING_KEY, DEFAULT_REQUIRE_CHARGING),
)
}
}

View File

@@ -8,7 +8,6 @@ import android.net.Uri
import android.os.Build
import android.os.CancellationSignal
import android.os.OperationCanceledException
import android.provider.MediaStore
import android.provider.MediaStore.Images
import android.provider.MediaStore.Video
import android.util.Size
@@ -19,7 +18,6 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DecodeFormat
import java.util.Base64
import java.util.HashMap
import java.util.concurrent.CancellationException
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Future
@@ -202,8 +200,10 @@ class ThumbnailsImpl(context: Context) : ThumbnailApi {
val source = ImageDecoder.createSource(resolver, uri)
signal.throwIfCanceled()
ImageDecoder.decodeBitmap(source) { decoder, info, _ ->
val sampleSize = max(1, min(info.size.width / targetWidth, info.size.height / targetHeight))
decoder.setTargetSampleSize(sampleSize)
if (targetWidth > 0 && targetHeight > 0) {
val sample = max(1, min(info.size.width / targetWidth, info.size.height / targetHeight))
decoder.setTargetSampleSize(sample)
}
decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
decoder.setTargetColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
}

View File

@@ -209,6 +209,40 @@ data class SyncDelta (
override fun hashCode(): Int = toList().hashCode()
}
/** Generated class from Pigeon that represents data sent in messages. */
data class HashResult (
val assetId: String,
val error: String? = null,
val hash: String? = null
)
{
companion object {
fun fromList(pigeonVar_list: List<Any?>): HashResult {
val assetId = pigeonVar_list[0] as String
val error = pigeonVar_list[1] as String?
val hash = pigeonVar_list[2] as String?
return HashResult(assetId, error, hash)
}
}
fun toList(): List<Any?> {
return listOf(
assetId,
error,
hash,
)
}
override fun equals(other: Any?): Boolean {
if (other !is HashResult) {
return false
}
if (this === other) {
return true
}
return MessagesPigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
}
private open class MessagesPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
@@ -227,6 +261,11 @@ private open class MessagesPigeonCodec : StandardMessageCodec() {
SyncDelta.fromList(it)
}
}
132.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
HashResult.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
}
}
@@ -244,11 +283,16 @@ private open class MessagesPigeonCodec : StandardMessageCodec() {
stream.write(131)
writeValue(stream, value.toList())
}
is HashResult -> {
stream.write(132)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface NativeSyncApi {
fun shouldFullSync(): Boolean
@@ -259,7 +303,8 @@ interface NativeSyncApi {
fun getAlbums(): List<PlatformAlbum>
fun getAssetsCountSince(albumId: String, timestamp: Long): Long
fun getAssetsForAlbum(albumId: String, updatedTimeCond: Long?): List<PlatformAsset>
fun hashPaths(paths: List<String>): List<ByteArray?>
fun hashAssets(assetIds: List<String>, allowNetworkAccess: Boolean, callback: (Result<List<HashResult>>) -> Unit)
fun cancelHashing()
companion object {
/** The codec used by NativeSyncApi. */
@@ -402,13 +447,33 @@ interface NativeSyncApi {
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.NativeSyncApi.hashPaths$separatedMessageChannelSuffix", codec, taskQueue)
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.NativeSyncApi.hashAssets$separatedMessageChannelSuffix", codec, taskQueue)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val pathsArg = args[0] as List<String>
val assetIdsArg = args[0] as List<String>
val allowNetworkAccessArg = args[1] as Boolean
api.hashAssets(assetIdsArg, allowNetworkAccessArg) { result: Result<List<HashResult>> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(MessagesPigeonUtils.wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(MessagesPigeonUtils.wrapResult(data))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.NativeSyncApi.cancelHashing$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
listOf(api.hashPaths(pathsArg))
api.cancelHashing()
listOf(null)
} catch (exception: Throwable) {
MessagesPigeonUtils.wrapError(exception)
}

View File

@@ -1,14 +1,25 @@
package app.alextran.immich.sync
import android.annotation.SuppressLint
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.provider.MediaStore
import android.util.Log
import android.util.Base64
import androidx.core.database.getStringOrNull
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import java.io.File
import java.io.FileInputStream
import java.security.MessageDigest
import kotlin.coroutines.cancellation.CancellationException
import kotlin.coroutines.coroutineContext
sealed class AssetResult {
data class ValidAsset(val asset: PlatformAsset, val albumId: String) : AssetResult()
@@ -19,8 +30,12 @@ sealed class AssetResult {
open class NativeSyncApiImplBase(context: Context) {
private val ctx: Context = context.applicationContext
private var hashTask: Job? = null
companion object {
private const val TAG = "NativeSyncApiImplBase"
private const val MAX_CONCURRENT_HASH_OPERATIONS = 16
private val hashSemaphore = Semaphore(MAX_CONCURRENT_HASH_OPERATIONS)
private const val HASHING_CANCELLED_CODE = "HASH_CANCELLED"
const val MEDIA_SELECTION =
"(${MediaStore.Files.FileColumns.MEDIA_TYPE} = ? OR ${MediaStore.Files.FileColumns.MEDIA_TYPE} = ?)"
@@ -215,23 +230,74 @@ open class NativeSyncApiImplBase(context: Context) {
.toList()
}
fun hashPaths(paths: List<String>): List<ByteArray?> {
val buffer = ByteArray(HASH_BUFFER_SIZE)
val digest = MessageDigest.getInstance("SHA-1")
fun hashAssets(
assetIds: List<String>,
// allowNetworkAccess is only used on the iOS implementation
@Suppress("UNUSED_PARAMETER") allowNetworkAccess: Boolean,
callback: (Result<List<HashResult>>) -> Unit
) {
if (assetIds.isEmpty()) {
callback(Result.success(emptyList()))
return
}
return paths.map { path ->
hashTask?.cancel()
hashTask = CoroutineScope(Dispatchers.IO).launch {
try {
FileInputStream(path).use { file ->
var bytesRead: Int
while (file.read(buffer).also { bytesRead = it } > 0) {
digest.update(buffer, 0, bytesRead)
val results = assetIds.map { assetId ->
async {
hashSemaphore.withPermit {
ensureActive()
hashAsset(assetId)
}
}
}
digest.digest()
}.awaitAll()
callback(Result.success(results))
} catch (e: CancellationException) {
callback(
Result.failure(
FlutterError(
HASHING_CANCELLED_CODE,
"Hashing operation was cancelled",
null
)
)
)
} catch (e: Exception) {
Log.w(TAG, "Failed to hash file $path: $e")
null
callback(Result.failure(e))
}
}
}
private suspend fun hashAsset(assetId: String): HashResult {
return try {
val assetUri = ContentUris.withAppendedId(
MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL),
assetId.toLong()
)
val digest = MessageDigest.getInstance("SHA-1")
ctx.contentResolver.openInputStream(assetUri)?.use { inputStream ->
var bytesRead: Int
val buffer = ByteArray(HASH_BUFFER_SIZE)
while (inputStream.read(buffer).also { bytesRead = it } > 0) {
coroutineContext.ensureActive()
digest.update(buffer, 0, bytesRead)
}
} ?: return HashResult(assetId, "Cannot open input stream for asset", null)
val hashString = Base64.encodeToString(digest.digest(), Base64.NO_WRAP)
HashResult(assetId, null, hashString)
} catch (e: SecurityException) {
HashResult(assetId, "Permission denied accessing asset: ${e.message}", null)
} catch (e: Exception) {
HashResult(assetId, "Failed to hash asset: ${e.message}", null)
}
}
fun cancelHashing() {
hashTask?.cancel()
hashTask = null
}
}

View File

@@ -35,8 +35,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 3013,
"android.injected.version.name" => "1.141.1",
"android.injected.version.code" => 3015,
"android.injected.version.name" => "1.142.1",
}
)
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')

View File

@@ -4,7 +4,6 @@
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/

View File

@@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
<string>13.0</string>
</dict>
</plist>

View File

@@ -253,7 +253,7 @@ SPEC CHECKSUMS:
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 77;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -133,6 +133,8 @@
/* Begin PBXFileSystemSynchronizedRootGroup section */
B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
path = Sync;
sourceTree = "<group>";
};
@@ -519,14 +521,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
@@ -555,14 +553,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
@@ -711,7 +705,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
@@ -855,7 +849,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
@@ -885,7 +879,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
@@ -919,7 +913,7 @@
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -962,7 +956,7 @@
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -1002,7 +996,7 @@
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -1041,7 +1035,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1085,7 +1079,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1126,7 +1120,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 219;
CURRENT_PROJECT_VERSION = 224;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;

View File

@@ -50,11 +50,119 @@ private func nilOrValue<T>(_ value: Any?) -> T? {
return value as! T?
}
func deepEqualsBackgroundWorker(_ lhs: Any?, _ rhs: Any?) -> Bool {
let cleanLhs = nilOrValue(lhs) as Any?
let cleanRhs = nilOrValue(rhs) as Any?
switch (cleanLhs, cleanRhs) {
case (nil, nil):
return true
case (nil, _), (_, nil):
return false
case is (Void, Void):
return true
case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable):
return cleanLhsHashable == cleanRhsHashable
case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]):
guard cleanLhsArray.count == cleanRhsArray.count else { return false }
for (index, element) in cleanLhsArray.enumerated() {
if !deepEqualsBackgroundWorker(element, cleanRhsArray[index]) {
return false
}
}
return true
case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]):
guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false }
for (key, cleanLhsValue) in cleanLhsDictionary {
guard cleanRhsDictionary.index(forKey: key) != nil else { return false }
if !deepEqualsBackgroundWorker(cleanLhsValue, cleanRhsDictionary[key]!) {
return false
}
}
return true
default:
// Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue.
return false
}
}
func deepHashBackgroundWorker(value: Any?, hasher: inout Hasher) {
if let valueList = value as? [AnyHashable] {
for item in valueList { deepHashBackgroundWorker(value: item, hasher: &hasher) }
return
}
if let valueDict = value as? [AnyHashable: AnyHashable] {
for key in valueDict.keys {
hasher.combine(key)
deepHashBackgroundWorker(value: valueDict[key]!, hasher: &hasher)
}
return
}
if let hashableValue = value as? AnyHashable {
hasher.combine(hashableValue.hashValue)
}
return hasher.combine(String(describing: value))
}
/// Generated class from Pigeon that represents data sent in messages.
struct BackgroundWorkerSettings: Hashable {
var requiresCharging: Bool
var minimumDelaySeconds: Int64
// swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> BackgroundWorkerSettings? {
let requiresCharging = pigeonVar_list[0] as! Bool
let minimumDelaySeconds = pigeonVar_list[1] as! Int64
return BackgroundWorkerSettings(
requiresCharging: requiresCharging,
minimumDelaySeconds: minimumDelaySeconds
)
}
func toList() -> [Any?] {
return [
requiresCharging,
minimumDelaySeconds,
]
}
static func == (lhs: BackgroundWorkerSettings, rhs: BackgroundWorkerSettings) -> Bool {
return deepEqualsBackgroundWorker(lhs.toList(), rhs.toList()) }
func hash(into hasher: inout Hasher) {
deepHashBackgroundWorker(value: toList(), hasher: &hasher)
}
}
private class BackgroundWorkerPigeonCodecReader: FlutterStandardReader {
override func readValue(ofType type: UInt8) -> Any? {
switch type {
case 129:
return BackgroundWorkerSettings.fromList(self.readValue() as! [Any?])
default:
return super.readValue(ofType: type)
}
}
}
private class BackgroundWorkerPigeonCodecWriter: FlutterStandardWriter {
override func writeValue(_ value: Any) {
if let value = value as? BackgroundWorkerSettings {
super.writeByte(129)
super.writeValue(value.toList())
} else {
super.writeValue(value)
}
}
}
private class BackgroundWorkerPigeonCodecReaderWriter: FlutterStandardReaderWriter {
@@ -74,6 +182,7 @@ class BackgroundWorkerPigeonCodec: FlutterStandardMessageCodec, @unchecked Senda
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
protocol BackgroundWorkerFgHostApi {
func enable() throws
func configure(settings: BackgroundWorkerSettings) throws
func disable() throws
}
@@ -96,6 +205,21 @@ class BackgroundWorkerFgHostApiSetup {
} else {
enableChannel.setMessageHandler(nil)
}
let configureChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.configure\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
configureChannel.setMessageHandler { message, reply in
let args = message as! [Any?]
let settingsArg = args[0] as! BackgroundWorkerSettings
do {
try api.configure(settings: settingsArg)
reply(wrapResult(nil))
} catch {
reply(wrapError(error))
}
}
} else {
configureChannel.setMessageHandler(nil)
}
let disableChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.disable\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
disableChannel.setMessageHandler { _, reply in

View File

@@ -133,7 +133,6 @@ class BackgroundWorker: BackgroundWorkerBgHostApi {
return
}
isComplete = true
flutterApi?.cancel { result in
self.complete(success: false)
}
@@ -174,6 +173,7 @@ class BackgroundWorker: BackgroundWorkerBgHostApi {
isComplete = true
engine.destroyContext()
flutterApi = nil
completionHandler(success)
}
}

View File

@@ -5,17 +5,22 @@ class BackgroundWorkerApiImpl: BackgroundWorkerFgHostApi {
func enable() throws {
BackgroundWorkerApiImpl.scheduleRefreshWorker()
BackgroundWorkerApiImpl.scheduleProcessingWorker()
print("BackgroundUploadImpl:enbale Background worker scheduled")
print("BackgroundWorkerApiImpl:enable Background worker scheduled")
}
func configure(settings: BackgroundWorkerSettings) throws {
// Android only
}
func disable() throws {
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: BackgroundWorkerApiImpl.refreshTaskID);
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: BackgroundWorkerApiImpl.processingTaskID);
print("BackgroundUploadImpl:disableUploadWorker Disabled background workers")
print("BackgroundWorkerApiImpl:disableUploadWorker Disabled background workers")
}
private static let refreshTaskID = "app.alextran.immich.background.refreshUpload"
private static let processingTaskID = "app.alextran.immich.background.processingUpload"
private static let taskSemaphore = DispatchSemaphore(value: 1)
public static func registerBackgroundWorkers() {
BGTaskScheduler.shared.register(
@@ -59,12 +64,18 @@ class BackgroundWorkerApiImpl: BackgroundWorkerFgHostApi {
private static func handleBackgroundRefresh(task: BGAppRefreshTask) {
scheduleRefreshWorker()
// Restrict the refresh task to run only for a maximum of (maxSeconds) seconds
runBackgroundWorker(task: task, taskType: .refresh, maxSeconds: 20)
// If another task is running, cede the background time back to the OS
if taskSemaphore.wait(timeout: .now()) == .success {
// Restrict the refresh task to run only for a maximum of (maxSeconds) seconds
runBackgroundWorker(task: task, taskType: .refresh, maxSeconds: 20)
} else {
task.setTaskCompleted(success: false)
}
}
private static func handleBackgroundProcessing(task: BGProcessingTask) {
scheduleProcessingWorker()
taskSemaphore.wait()
// There are no restrictions for processing tasks. Although, the OS could signal expiration at any time
runBackgroundWorker(task: task, taskType: .processing, maxSeconds: nil)
}
@@ -80,6 +91,7 @@ class BackgroundWorkerApiImpl: BackgroundWorkerFgHostApi {
* - maxSeconds: Optional timeout for the operation in seconds
*/
private static func runBackgroundWorker(task: BGTask, taskType: BackgroundTaskType, maxSeconds: Int?) {
defer { taskSemaphore.signal() }
let semaphore = DispatchSemaphore(value: 0)
var isSuccess = true

View File

@@ -105,7 +105,7 @@ class ThumbnailApiImpl: ThumbnailApi {
var image: UIImage?
Self.imageManager.requestImage(
for: asset,
targetSize: CGSize(width: Double(width), height: Double(height)),
targetSize: width > 0 && height > 0 ? CGSize(width: Double(width), height: Double(height)) : PHImageManagerMaximumSize,
contentMode: .aspectFill,
options: Self.requestOptions,
resultHandler: { (_image, info) -> Void in

View File

@@ -80,7 +80,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.140.0</string>
<string>1.142.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@@ -107,7 +107,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>219</string>
<string>224</string>
<key>FLTEnableImpeller</key>
<true/>
<key>ITSAppUsesNonExemptEncryption</key>

View File

@@ -267,6 +267,39 @@ struct SyncDelta: Hashable {
}
}
/// Generated class from Pigeon that represents data sent in messages.
struct HashResult: Hashable {
var assetId: String
var error: String? = nil
var hash: String? = nil
// swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> HashResult? {
let assetId = pigeonVar_list[0] as! String
let error: String? = nilOrValue(pigeonVar_list[1])
let hash: String? = nilOrValue(pigeonVar_list[2])
return HashResult(
assetId: assetId,
error: error,
hash: hash
)
}
func toList() -> [Any?] {
return [
assetId,
error,
hash,
]
}
static func == (lhs: HashResult, rhs: HashResult) -> Bool {
return deepEqualsMessages(lhs.toList(), rhs.toList()) }
func hash(into hasher: inout Hasher) {
deepHashMessages(value: toList(), hasher: &hasher)
}
}
private class MessagesPigeonCodecReader: FlutterStandardReader {
override func readValue(ofType type: UInt8) -> Any? {
switch type {
@@ -276,6 +309,8 @@ private class MessagesPigeonCodecReader: FlutterStandardReader {
return PlatformAlbum.fromList(self.readValue() as! [Any?])
case 131:
return SyncDelta.fromList(self.readValue() as! [Any?])
case 132:
return HashResult.fromList(self.readValue() as! [Any?])
default:
return super.readValue(ofType: type)
}
@@ -293,6 +328,9 @@ private class MessagesPigeonCodecWriter: FlutterStandardWriter {
} else if let value = value as? SyncDelta {
super.writeByte(131)
super.writeValue(value.toList())
} else if let value = value as? HashResult {
super.writeByte(132)
super.writeValue(value.toList())
} else {
super.writeValue(value)
}
@@ -313,6 +351,7 @@ class MessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable {
static let shared = MessagesPigeonCodec(readerWriter: MessagesPigeonCodecReaderWriter())
}
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
protocol NativeSyncApi {
func shouldFullSync() throws -> Bool
@@ -323,7 +362,8 @@ protocol NativeSyncApi {
func getAlbums() throws -> [PlatformAlbum]
func getAssetsCountSince(albumId: String, timestamp: Int64) throws -> Int64
func getAssetsForAlbum(albumId: String, updatedTimeCond: Int64?) throws -> [PlatformAsset]
func hashPaths(paths: [String]) throws -> [FlutterStandardTypedData?]
func hashAssets(assetIds: [String], allowNetworkAccess: Bool, completion: @escaping (Result<[HashResult], Error>) -> Void)
func cancelHashing() throws
}
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -459,22 +499,38 @@ class NativeSyncApiSetup {
} else {
getAssetsForAlbumChannel.setMessageHandler(nil)
}
let hashPathsChannel = taskQueue == nil
? FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.NativeSyncApi.hashPaths\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
: FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.NativeSyncApi.hashPaths\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec, taskQueue: taskQueue)
let hashAssetsChannel = taskQueue == nil
? FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.NativeSyncApi.hashAssets\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
: FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.NativeSyncApi.hashAssets\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec, taskQueue: taskQueue)
if let api = api {
hashPathsChannel.setMessageHandler { message, reply in
hashAssetsChannel.setMessageHandler { message, reply in
let args = message as! [Any?]
let pathsArg = args[0] as! [String]
let assetIdsArg = args[0] as! [String]
let allowNetworkAccessArg = args[1] as! Bool
api.hashAssets(assetIds: assetIdsArg, allowNetworkAccess: allowNetworkAccessArg) { result in
switch result {
case .success(let res):
reply(wrapResult(res))
case .failure(let error):
reply(wrapError(error))
}
}
}
} else {
hashAssetsChannel.setMessageHandler(nil)
}
let cancelHashingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.NativeSyncApi.cancelHashing\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
cancelHashingChannel.setMessageHandler { _, reply in
do {
let result = try api.hashPaths(paths: pathsArg)
reply(wrapResult(result))
try api.cancelHashing()
reply(wrapResult(nil))
} catch {
reply(wrapError(error))
}
}
} else {
hashPathsChannel.setMessageHandler(nil)
cancelHashingChannel.setMessageHandler(nil)
}
}
}

View File

@@ -17,30 +17,16 @@ struct AssetWrapper: Hashable, Equatable {
}
}
extension PHAsset {
func toPlatformAsset() -> PlatformAsset {
return PlatformAsset(
id: localIdentifier,
name: title(),
type: Int64(mediaType.rawValue),
createdAt: creationDate.map { Int64($0.timeIntervalSince1970) },
updatedAt: modificationDate.map { Int64($0.timeIntervalSince1970) },
width: Int64(pixelWidth),
height: Int64(pixelHeight),
durationInSeconds: Int64(duration),
orientation: 0,
isFavorite: isFavorite
)
}
}
class NativeSyncApiImpl: NativeSyncApi {
private let defaults: UserDefaults
private let changeTokenKey = "immich:changeToken"
private let albumTypes: [PHAssetCollectionType] = [.album, .smartAlbum]
private let recoveredAlbumSubType = 1000000219
private let hashBufferSize = 2 * 1024 * 1024
private var hashTask: Task<Void, Error>?
private static let hashCancelledCode = "HASH_CANCELLED"
private static let hashCancelled = Result<[HashResult], Error>.failure(PigeonError(code: hashCancelledCode, message: "Hashing cancelled", details: nil))
init(with defaults: UserDefaults = .standard) {
self.defaults = defaults
@@ -96,7 +82,7 @@ class NativeSyncApiImpl: NativeSyncApi {
let collections = PHAssetCollection.fetchAssetCollections(with: type, subtype: .any, options: nil)
for i in 0..<collections.count {
let album = collections.object(at: i)
// Ignore recovered album
if(album.assetCollectionSubtype.rawValue == self.recoveredAlbumSubType) {
continue;
@@ -254,7 +240,7 @@ class NativeSyncApiImpl: NativeSyncApi {
let date = NSDate(timeIntervalSince1970: TimeInterval(updatedTimeCond!))
options.predicate = NSPredicate(format: "creationDate > %@ OR modificationDate > %@", date, date)
}
let result = PHAsset.fetchAssets(in: album, options: options)
if(result.count == 0) {
return []
@@ -267,23 +253,114 @@ class NativeSyncApiImpl: NativeSyncApi {
return assets
}
func hashPaths(paths: [String]) throws -> [FlutterStandardTypedData?] {
return paths.map { path in
guard let file = FileHandle(forReadingAtPath: path) else {
print("Cannot open file: \(path)")
return nil
}
var hasher = Insecure.SHA1()
while autoreleasepool(invoking: {
let chunk = file.readData(ofLength: hashBufferSize)
guard !chunk.isEmpty else { return false }
hasher.update(data: chunk)
return true
}) { }
let digest = hasher.finalize()
return FlutterStandardTypedData(bytes: Data(digest))
func hashAssets(assetIds: [String], allowNetworkAccess: Bool, completion: @escaping (Result<[HashResult], Error>) -> Void) {
if let prevTask = hashTask {
prevTask.cancel()
hashTask = nil
}
hashTask = Task { [weak self] in
var missingAssetIds = Set(assetIds)
var assets = [PHAsset]()
assets.reserveCapacity(assetIds.count)
PHAsset.fetchAssets(withLocalIdentifiers: assetIds, options: nil).enumerateObjects { (asset, _, stop) in
if Task.isCancelled {
stop.pointee = true
return
}
missingAssetIds.remove(asset.localIdentifier)
assets.append(asset)
}
if Task.isCancelled {
return completion(Self.hashCancelled)
}
await withTaskGroup(of: HashResult?.self) { taskGroup in
var results = [HashResult]()
results.reserveCapacity(assets.count)
for asset in assets {
if Task.isCancelled {
return completion(Self.hashCancelled)
}
taskGroup.addTask {
guard let self = self else { return nil }
return await self.hashAsset(asset, allowNetworkAccess: allowNetworkAccess)
}
}
for await result in taskGroup {
guard let result = result else {
return completion(Self.hashCancelled)
}
results.append(result)
}
for missing in missingAssetIds {
results.append(HashResult(assetId: missing, error: "Asset not found in library", hash: nil))
}
completion(.success(results))
}
}
}
func cancelHashing() {
hashTask?.cancel()
hashTask = nil
}
private func hashAsset(_ asset: PHAsset, allowNetworkAccess: Bool) async -> HashResult? {
class RequestRef {
var id: PHAssetResourceDataRequestID?
}
let requestRef = RequestRef()
return await withTaskCancellationHandler(operation: {
if Task.isCancelled {
return nil
}
guard let resource = asset.getResource() else {
return HashResult(assetId: asset.localIdentifier, error: "Cannot get asset resource", hash: nil)
}
if Task.isCancelled {
return nil
}
let options = PHAssetResourceRequestOptions()
options.isNetworkAccessAllowed = allowNetworkAccess
return await withCheckedContinuation { continuation in
var hasher = Insecure.SHA1()
requestRef.id = PHAssetResourceManager.default().requestData(
for: resource,
options: options,
dataReceivedHandler: { data in
hasher.update(data: data)
},
completionHandler: { error in
let result: HashResult? = switch (error) {
case let e as PHPhotosError where e.code == .userCancelled: nil
case let .some(e): HashResult(
assetId: asset.localIdentifier,
error: "Failed to hash asset: \(e.localizedDescription)",
hash: nil
)
case .none:
HashResult(
assetId: asset.localIdentifier,
error: nil,
hash: Data(hasher.finalize()).base64EncodedString()
)
}
continuation.resume(returning: result)
}
)
}
}, onCancel: {
guard let requestId = requestRef.id else { return }
PHAssetResourceManager.default().cancelDataRequest(requestId)
})
}
}

View File

@@ -0,0 +1,77 @@
import Photos
extension PHAsset {
func toPlatformAsset() -> PlatformAsset {
return PlatformAsset(
id: localIdentifier,
name: title,
type: Int64(mediaType.rawValue),
createdAt: creationDate.map { Int64($0.timeIntervalSince1970) },
updatedAt: modificationDate.map { Int64($0.timeIntervalSince1970) },
width: Int64(pixelWidth),
height: Int64(pixelHeight),
durationInSeconds: Int64(duration),
orientation: 0,
isFavorite: isFavorite
)
}
var title: String {
return filename ?? originalFilename ?? "<unknown>"
}
var filename: String? {
return value(forKey: "filename") as? String
}
// This method is expected to be slow as it goes through the asset resources to fetch the originalFilename
var originalFilename: String? {
return getResource()?.originalFilename
}
func getResource() -> PHAssetResource? {
let resources = PHAssetResource.assetResources(for: self)
let filteredResources = resources.filter { $0.isMediaResource && isValidResourceType($0.type) }
guard !filteredResources.isEmpty else {
return nil
}
if filteredResources.count == 1 {
return filteredResources.first
}
if let currentResource = filteredResources.first(where: { $0.isCurrent }) {
return currentResource
}
if let fullSizeResource = filteredResources.first(where: { isFullSizeResourceType($0.type) }) {
return fullSizeResource
}
return nil
}
private func isValidResourceType(_ type: PHAssetResourceType) -> Bool {
switch mediaType {
case .image:
return [.photo, .alternatePhoto, .fullSizePhoto].contains(type)
case .video:
return [.video, .fullSizeVideo, .fullSizePairedVideo].contains(type)
default:
return false
}
}
private func isFullSizeResourceType(_ type: PHAssetResourceType) -> Bool {
switch mediaType {
case .image:
return type == .fullSizePhoto
case .video:
return type == .fullSizeVideo
default:
return false
}
}
}

View File

@@ -0,0 +1,16 @@
import Photos
extension PHAssetResource {
var isCurrent: Bool {
return value(forKey: "isCurrent") as? Bool ?? false
}
var isMediaResource: Bool {
var isMedia = type != .adjustmentData
if #available(iOS 17, *) {
isMedia = isMedia && type != .photoProxy
}
return isMedia
}
}

View File

@@ -22,7 +22,7 @@ platform :ios do
path: "./Runner.xcodeproj",
)
increment_version_number(
version_number: "1.141.1"
version_number: "1.142.1"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,

View File

@@ -1,3 +1,5 @@
import 'dart:io';
const int noDbId = -9223372036854775808; // from Isar
const double downloadCompleted = -1;
const double downloadFailed = -2;
@@ -10,7 +12,7 @@ const int kSyncEventBatchSize = 5000;
const int kFetchLocalAssetsBatchSize = 40000;
// Hash batch limits
const int kBatchHashFileLimit = 256;
final int kBatchHashFileLimit = Platform.isIOS ? 32 : 512;
const int kBatchHashSizeLimit = 1024 * 1024 * 1024; // 1GB
// Secure storage keys
@@ -45,3 +47,5 @@ const List<(String, String)> kWidgetNames = [
const double kUploadStatusFailed = -1.0;
const double kUploadStatusCanceled = -2.0;
const int kMinMonthsToEnableScrubberSnap = 12;

View File

@@ -77,7 +77,9 @@ enum StoreKey<T> {
enableBackup<bool>._(1003),
useWifiForUploadVideos<bool>._(1004),
useWifiForUploadPhotos<bool>._(1005),
needBetaMigration<bool>._(1006);
needBetaMigration<bool>._(1006),
// TODO: Remove this after patching open-api
shouldResetSync<bool>._(1007);
const StoreKey._(this.id);
final int id;

View File

@@ -1,22 +1,20 @@
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/extensions/platform_extensions.dart';
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/remote_asset.repository.dart';
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
import 'package:platform/platform.dart';
class AssetService {
final RemoteAssetRepository _remoteAssetRepository;
final DriftLocalAssetRepository _localAssetRepository;
final Platform _platform;
const AssetService({
required RemoteAssetRepository remoteAssetRepository,
required DriftLocalAssetRepository localAssetRepository,
}) : _remoteAssetRepository = remoteAssetRepository,
_localAssetRepository = localAssetRepository,
_platform = const LocalPlatform();
_localAssetRepository = localAssetRepository;
Future<BaseAsset?> getAsset(BaseAsset asset) {
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id;
@@ -42,13 +40,12 @@ class AssetService {
Future<List<RemoteAsset>> getStack(RemoteAsset asset) async {
if (asset.stackId == null) {
return [];
return const [];
}
return _remoteAssetRepository.getStackChildren(asset).then((assets) {
// Include the primary asset in the stack as the first item
return [asset, ...assets];
});
final stack = await _remoteAssetRepository.getStackChildren(asset);
// Include the primary asset in the stack as the first item
return [asset, ...stack];
}
Future<ExifInfo?> getExif(BaseAsset asset) async {
@@ -71,7 +68,7 @@ class AssetService {
width = exif?.width ?? asset.width?.toDouble();
height = exif?.height ?? asset.height?.toDouble();
} else if (asset is LocalAsset) {
isFlipped = _platform.isAndroid && (asset.orientation == 90 || asset.orientation == 270);
isFlipped = CurrentPlatform.isAndroid && (asset.orientation == 90 || asset.orientation == 270);
width = asset.width?.toDouble();
height = asset.height?.toDouble();
} else {

View File

@@ -7,6 +7,8 @@ import 'package:cancellation_token_http/http.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/constants.dart';
import 'package:immich_mobile/domain/services/log.service.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/extensions/network_capability_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/intl_keys.g.dart';
@@ -27,6 +29,7 @@ import 'package:immich_mobile/services/localization.service.dart';
import 'package:immich_mobile/services/server_info.service.dart';
import 'package:immich_mobile/services/upload.service.dart';
import 'package:immich_mobile/utils/bootstrap.dart';
import 'package:immich_mobile/utils/debug_print.dart';
import 'package:immich_mobile/utils/http_ssl_options.dart';
import 'package:isar/isar.dart';
import 'package:logging/logging.dart';
@@ -40,6 +43,17 @@ class BackgroundWorkerFgService {
// TODO: Move this call to native side once old timeline is removed
Future<void> enable() => _foregroundHostApi.enable();
Future<void> configure({int? minimumDelaySeconds, bool? requireCharging}) => _foregroundHostApi.configure(
BackgroundWorkerSettings(
minimumDelaySeconds:
minimumDelaySeconds ??
Store.get(AppSettingsEnum.backupTriggerDelay.storeKey, AppSettingsEnum.backupTriggerDelay.defaultValue),
requiresCharging:
requireCharging ??
Store.get(AppSettingsEnum.backupRequireCharging.storeKey, AppSettingsEnum.backupRequireCharging.defaultValue),
),
);
Future<void> disable() => _foregroundHostApi.disable();
}
@@ -159,7 +173,7 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
try {
await _cleanup();
} catch (error, stack) {
debugPrint('Failed to cleanup background worker: $error with stack: $stack');
dPrint(() => 'Failed to cleanup background worker: $error with stack: $stack');
}
}
@@ -169,7 +183,11 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
}
try {
final backgroundSyncManager = _ref.read(backgroundSyncProvider);
final nativeSyncApi = _ref.read(nativeSyncApiProvider);
_isCleanedUp = true;
_ref.dispose();
_cancellationToken.cancel();
_logger.info("Cleaning up background worker");
final cleanupFutures = [
@@ -177,53 +195,61 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
// Discard any errors on the dispose call
return;
}),
LogService.I.dispose(),
Store.dispose(),
_drift.close(),
_driftLogger.close(),
_ref.read(backgroundSyncProvider).cancel(),
_ref.read(backgroundSyncProvider).cancelLocal(),
backgroundSyncManager.cancel(),
nativeSyncApi.cancelHashing(),
];
if (_isar.isOpen) {
cleanupFutures.add(_isar.close());
}
_ref.dispose();
await Future.wait(cleanupFutures);
_logger.info("Background worker resources cleaned up");
} catch (error, stack) {
debugPrint('Failed to cleanup background worker: $error with stack: $stack');
dPrint(() => 'Failed to cleanup background worker: $error with stack: $stack');
}
}
Future<void> _handleBackup() async {
if (!_isBackupEnabled || _isCleanedUp) {
_logger.info("[_handleBackup 1] Backup is disabled. Skipping backup routine");
return;
}
await runZonedGuarded(
() async {
if (!_isBackupEnabled || _isCleanedUp) {
_logger.info("[_handleBackup 1] Backup is disabled. Skipping backup routine");
return;
}
_logger.info("[_handleBackup 2] Enqueuing assets for backup from the background service");
_logger.info("[_handleBackup 2] Enqueuing assets for backup from the background service");
final currentUser = _ref.read(currentUserProvider);
if (currentUser == null) {
_logger.warning("[_handleBackup 3] No current user found. Skipping backup from background");
return;
}
final currentUser = _ref.read(currentUserProvider);
if (currentUser == null) {
_logger.warning("[_handleBackup 3] No current user found. Skipping backup from background");
return;
}
_logger.info("[_handleBackup 4] Resume backup from background");
if (Platform.isIOS) {
return _ref.read(driftBackupProvider.notifier).handleBackupResume(currentUser.id);
}
_logger.info("[_handleBackup 4] Resume backup from background");
if (Platform.isIOS) {
return _ref.read(driftBackupProvider.notifier).handleBackupResume(currentUser.id);
}
final canPing = await _ref.read(serverInfoServiceProvider).ping();
if (!canPing) {
_logger.warning("[_handleBackup 5] Server is not reachable. Skipping backup from background");
return;
}
final canPing = await _ref.read(serverInfoServiceProvider).ping();
if (!canPing) {
_logger.warning("[_handleBackup 5] Server is not reachable. Skipping backup from background");
return;
}
final networkCapabilities = await _ref.read(connectivityApiProvider).getCapabilities();
final networkCapabilities = await _ref.read(connectivityApiProvider).getCapabilities();
return _ref
.read(uploadServiceProvider)
.startBackupWithHttpClient(currentUser.id, networkCapabilities.hasWifi, _cancellationToken);
return _ref
.read(uploadServiceProvider)
.startBackupWithHttpClient(currentUser.id, networkCapabilities.hasWifi, _cancellationToken);
},
(error, stack) {
dPrint(() => "Error in backup zone $error, $stack");
},
);
}
Future<void> _syncAssets({Duration? hashTimeout}) async {
@@ -259,6 +285,6 @@ Future<void> backgroundSyncNativeEntrypoint() async {
DartPluginRegistrant.ensureInitialized();
final (isar, drift, logDB) = await Bootstrap.initDB();
await Bootstrap.initDomain(isar, drift, logDB, shouldBufferLogs: false);
await Bootstrap.initDomain(isar, drift, logDB, shouldBufferLogs: false, listenStoreUpdates: false);
await BackgroundWorkerBgService(isar: isar, drift: drift, driftLogger: logDB).init();
}

View File

@@ -1,20 +1,18 @@
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:immich_mobile/constants/constants.dart';
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
import 'package:immich_mobile/platform/native_sync_api.g.dart';
import 'package:logging/logging.dart';
const String _kHashCancelledCode = "HASH_CANCELLED";
class HashService {
final int batchSizeLimit;
final int batchFileLimit;
final int _batchSize;
final DriftLocalAlbumRepository _localAlbumRepository;
final DriftLocalAssetRepository _localAssetRepository;
final StorageRepository _storageRepository;
final NativeSyncApi _nativeSyncApi;
final bool Function()? _cancelChecker;
final _log = Logger('HashService');
@@ -22,37 +20,42 @@ class HashService {
HashService({
required DriftLocalAlbumRepository localAlbumRepository,
required DriftLocalAssetRepository localAssetRepository,
required StorageRepository storageRepository,
required NativeSyncApi nativeSyncApi,
bool Function()? cancelChecker,
this.batchSizeLimit = kBatchHashSizeLimit,
this.batchFileLimit = kBatchHashFileLimit,
int? batchSize,
}) : _localAlbumRepository = localAlbumRepository,
_localAssetRepository = localAssetRepository,
_storageRepository = storageRepository,
_cancelChecker = cancelChecker,
_nativeSyncApi = nativeSyncApi;
_nativeSyncApi = nativeSyncApi,
_batchSize = batchSize ?? kBatchHashFileLimit;
bool get isCancelled => _cancelChecker?.call() ?? false;
Future<void> hashAssets() async {
_log.info("Starting hashing of assets");
final Stopwatch stopwatch = Stopwatch()..start();
// Sorted by backupSelection followed by isCloud
final localAlbums = await _localAlbumRepository.getAll(
sortBy: {SortLocalAlbumsBy.backupSelection, SortLocalAlbumsBy.isIosSharedAlbum},
);
try {
// Sorted by backupSelection followed by isCloud
final localAlbums = await _localAlbumRepository.getBackupAlbums();
for (final album in localAlbums) {
if (isCancelled) {
_log.warning("Hashing cancelled. Stopped processing albums.");
break;
}
for (final album in localAlbums) {
if (isCancelled) {
_log.warning("Hashing cancelled. Stopped processing albums.");
break;
}
final assetsToHash = await _localAlbumRepository.getAssetsToHash(album.id);
if (assetsToHash.isNotEmpty) {
await _hashAssets(album, assetsToHash);
final assetsToHash = await _localAlbumRepository.getAssetsToHash(album.id);
if (assetsToHash.isNotEmpty) {
await _hashAssets(album, assetsToHash);
}
}
} on PlatformException catch (e) {
if (e.code == _kHashCancelledCode) {
_log.warning("Hashing cancelled by platform");
return;
}
} catch (e, s) {
_log.severe("Error during hashing", e, s);
}
stopwatch.stop();
@@ -63,8 +66,7 @@ class HashService {
/// with hash for those that were successfully hashed. Hashes are looked up in a table
/// [LocalAssetHashEntity] by local id. Only missing entries are newly hashed and added to the DB.
Future<void> _hashAssets(LocalAlbum album, List<LocalAsset> assetsToHash) async {
int bytesProcessed = 0;
final toHash = <_AssetToPath>[];
final toHash = <String, LocalAsset>{};
for (final asset in assetsToHash) {
if (isCancelled) {
@@ -72,21 +74,10 @@ class HashService {
return;
}
final file = await _storageRepository.getFileForAsset(asset.id);
if (file == null) {
_log.warning(
"Cannot get file for asset ${asset.id}, name: ${asset.name}, created on: ${asset.createdAt} from album: ${album.name}",
);
continue;
}
bytesProcessed += await file.length();
toHash.add(_AssetToPath(asset: asset, path: file.path));
if (toHash.length >= batchFileLimit || bytesProcessed >= batchSizeLimit) {
toHash[asset.id] = asset;
if (toHash.length == _batchSize) {
await _processBatch(album, toHash);
toHash.clear();
bytesProcessed = 0;
}
}
@@ -94,33 +85,36 @@ class HashService {
}
/// Processes a batch of assets.
Future<void> _processBatch(LocalAlbum album, List<_AssetToPath> toHash) async {
Future<void> _processBatch(LocalAlbum album, Map<String, LocalAsset> toHash) async {
if (toHash.isEmpty) {
return;
}
_log.fine("Hashing ${toHash.length} files");
final hashed = <LocalAsset>[];
final hashes = await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList());
final hashed = <String, String>{};
final hashResults = await _nativeSyncApi.hashAssets(
toHash.keys.toList(),
allowNetworkAccess: album.backupSelection == BackupSelection.selected,
);
assert(
hashes.length == toHash.length,
"Hashes length does not match toHash length: ${hashes.length} != ${toHash.length}",
hashResults.length == toHash.length,
"Hashes length does not match toHash length: ${hashResults.length} != ${toHash.length}",
);
for (int i = 0; i < hashes.length; i++) {
for (int i = 0; i < hashResults.length; i++) {
if (isCancelled) {
_log.warning("Hashing cancelled. Stopped processing batch.");
return;
}
final hash = hashes[i];
final asset = toHash[i].asset;
if (hash?.length == 20) {
hashed.add(asset.copyWith(checksum: base64.encode(hash!)));
final hashResult = hashResults[i];
if (hashResult.hash != null) {
hashed[hashResult.assetId] = hashResult.hash!;
} else {
final asset = toHash[hashResult.assetId];
_log.warning(
"Failed to hash file for ${asset.id}: ${asset.name} created at ${asset.createdAt} from album: ${album.name}",
"Failed to hash asset with id: ${hashResult.assetId}, name: ${asset?.name}, createdAt: ${asset?.createdAt}, from album: ${album.name}. Error: ${hashResult.error ?? "unknown"}",
);
}
}
@@ -128,13 +122,5 @@ class HashService {
_log.fine("Hashed ${hashed.length}/${toHash.length} assets");
await _localAssetRepository.updateHashes(hashed);
await _storageRepository.clearCache();
}
}
class _AssetToPath {
final LocalAsset asset;
final String path;
const _AssetToPath({required this.asset, required this.path});
}

View File

@@ -1,29 +1,24 @@
import 'dart:async';
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/foundation.dart';
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/platform_extensions.dart';
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
import 'package:immich_mobile/platform/native_sync_api.g.dart';
import 'package:immich_mobile/utils/datetime_helpers.dart';
import 'package:immich_mobile/utils/diff.dart';
import 'package:logging/logging.dart';
import 'package:platform/platform.dart';
class LocalSyncService {
final DriftLocalAlbumRepository _localAlbumRepository;
final NativeSyncApi _nativeSyncApi;
final Platform _platform;
final Logger _log = Logger("DeviceSyncService");
LocalSyncService({
required DriftLocalAlbumRepository localAlbumRepository,
required NativeSyncApi nativeSyncApi,
Platform? platform,
}) : _localAlbumRepository = localAlbumRepository,
_nativeSyncApi = nativeSyncApi,
_platform = platform ?? const LocalPlatform();
LocalSyncService({required DriftLocalAlbumRepository localAlbumRepository, required NativeSyncApi nativeSyncApi})
: _localAlbumRepository = localAlbumRepository,
_nativeSyncApi = nativeSyncApi;
Future<void> sync({bool full = false}) async {
final Stopwatch stopwatch = Stopwatch()..start();
@@ -53,14 +48,14 @@ class LocalSyncService {
final dbAlbums = await _localAlbumRepository.getAll();
// On Android, we need to sync all albums since it is not possible to
// detect album deletions from the native side
if (_platform.isAndroid) {
if (CurrentPlatform.isAndroid) {
for (final album in dbAlbums) {
final deviceIds = await _nativeSyncApi.getAssetIdsForAlbum(album.id);
await _localAlbumRepository.syncDeletes(album.id, deviceIds);
}
}
if (_platform.isIOS) {
if (CurrentPlatform.isIOS) {
// 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,
// remove the albums from the local database from the previous sync

View File

@@ -1,11 +1,11 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:immich_mobile/constants/constants.dart';
import 'package:immich_mobile/domain/models/log.model.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
import 'package:immich_mobile/utils/debug_print.dart';
import 'package:logging/logging.dart';
/// Service responsible for handling application logging.
@@ -66,13 +66,12 @@ class LogService {
}
void _handleLogRecord(LogRecord r) {
if (kDebugMode) {
debugPrint(
'[${r.level.name}] [${r.time}] [${r.loggerName}] ${r.message}'
'${r.error == null ? '' : '\nError: ${r.error}'}'
'${r.stackTrace == null ? '' : '\nStack: ${r.stackTrace}'}',
);
}
dPrint(
() =>
'[${r.level.name}] [${r.time}] [${r.loggerName}] ${r.message}'
'${r.error == null ? '' : '\nError: ${r.error}'}'
'${r.stackTrace == null ? '' : '\nStack: ${r.stackTrace}'}',
);
final record = LogMessage(
message: r.message,

View File

@@ -1,7 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/infrastructure/repositories/partner.repository.dart';
import 'package:immich_mobile/repositories/partner_api.repository.dart';
import 'package:immich_mobile/utils/debug_print.dart';
class DriftPartnerService {
final DriftPartnerRepository _driftPartnerRepository;
@@ -30,7 +30,7 @@ class DriftPartnerService {
Future<void> toggleShowInTimeline(String partnerId, String userId) async {
final partner = await _driftPartnerRepository.getPartner(partnerId, userId);
if (partner == null) {
debugPrint("Partner not found: $partnerId for user: $userId");
dPrint(() => "Partner not found: $partnerId for user: $userId");
return;
}

View File

@@ -10,7 +10,7 @@ class StoreService {
/// In-memory cache. Keys are [StoreKey.id]
final Map<int, Object?> _cache = {};
late final StreamSubscription<List<StoreDto>> _storeUpdateSubscription;
StreamSubscription<List<StoreDto>>? _storeUpdateSubscription;
StoreService._({required IStoreRepository isarStoreRepository}) : _storeRepository = isarStoreRepository;
@@ -24,15 +24,17 @@ class StoreService {
}
// TODO: Replace the implementation with the one from create after removing the typedef
static Future<StoreService> init({required IStoreRepository storeRepository}) async {
_instance ??= await create(storeRepository: storeRepository);
static Future<StoreService> init({required IStoreRepository storeRepository, bool listenUpdates = true}) async {
_instance ??= await create(storeRepository: storeRepository, listenUpdates: listenUpdates);
return _instance!;
}
static Future<StoreService> create({required IStoreRepository storeRepository}) async {
static Future<StoreService> create({required IStoreRepository storeRepository, bool listenUpdates = true}) async {
final instance = StoreService._(isarStoreRepository: storeRepository);
await instance.populateCache();
instance._storeUpdateSubscription = instance._listenForChange();
if (listenUpdates) {
instance._storeUpdateSubscription = instance._listenForChange();
}
return instance;
}
@@ -50,8 +52,8 @@ class StoreService {
});
/// Disposes the store and cancels the subscription. To reuse the store call init() again
void dispose() async {
await _storeUpdateSubscription.cancel();
Future<void> dispose() async {
await _storeUpdateSubscription?.cancel();
_cache.clear();
}

View File

@@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
@@ -6,6 +5,7 @@ import 'package:immich_mobile/infrastructure/repositories/remote_album.repositor
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
import 'package:immich_mobile/repositories/drift_album_api_repository.dart';
import 'package:logging/logging.dart';
import 'package:immich_mobile/utils/debug_print.dart';
final syncLinkedAlbumServiceProvider = Provider(
(ref) => SyncLinkedAlbumService(
@@ -100,7 +100,7 @@ class SyncLinkedAlbumService {
/// Creates a new remote album and links it to the local album
Future<void> _createAndLinkNewRemoteAlbum(LocalAlbum localAlbum) async {
debugPrint("Creating new remote album for local album: ${localAlbum.name}");
dPrint(() => "Creating new remote album for local album: ${localAlbum.name}");
final newRemoteAlbum = await _albumApiRepository.createDriftAlbum(localAlbum.name, assetIds: []);
await _remoteAlbumRepository.create(newRemoteAlbum, []);
return _localAlbumRepository.linkRemoteAlbum(localAlbum.id, newRemoteAlbum.id);

View File

@@ -29,6 +29,7 @@ class SyncStreamService {
bool shouldReset = false;
await _syncApiRepository.streamChanges(_handleEvents, onReset: () => shouldReset = true);
if (shouldReset) {
_logger.info("Resetting sync state as requested by server");
await _syncApiRepository.streamChanges(_handleEvents);
}
}

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