Compare commits

...

657 Commits

Author SHA1 Message Date
mmomjian 2d309e91da change all refs 2025-04-22 17:43:12 -04:00
mmomjian a2c0ecfc2a translation keys 2025-04-22 12:16:00 -04:00
mmomjian 085f39dea6 fix 2025-04-22 11:45:52 -04:00
shenlong 81ed54aa61 feat: user sync stream (#16862)
* refactor: user entity

* chore: rebase fixes

* refactor: remove int user Id

* refactor: migrate store userId from int to string

* refactor: rename uid to id

* feat: drift

* pr feedback

* refactor: move common overrides to mixin

* refactor: remove int user Id

* refactor: migrate store userId from int to string

* refactor: rename uid to id

* feat: user & partner sync stream

* pr changes

* refactor: sync service and add tests

* chore: remove generated change

* chore: move sync model

* rebase: convert string ids to byte uuids

* rebase

* add processing logs

* batch db calls

* rewrite isolate manager

* rewrite with worker_manager

* misc fixes

* add sync order test

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-04-17 10:25:27 -05:00
Daniel Dietzler 067338b0ed chore: remove transfer encoding header (#17671) 2025-04-17 09:46:52 -05:00
Min Idzelis 5e68f8c519 fix: longpress triggers contextmenu (#17602) 2025-04-16 19:24:26 -04:00
Mert 242a559e0f refactor: query for fetching faces and people of assets (#17661)
* use json instead of jsonb

* missing condition
2025-04-16 19:00:55 -04:00
Jonathan Jogenfors ed2b54527c chore(server): don't check null dates (#17664) 2025-04-16 18:40:08 -04:00
Daniel Dietzler 8b38f8a58d fix: do not select album in time bucket query (#17662) 2025-04-16 17:52:22 -04:00
yparitcher 29b30570bf fix: use IMMICH_HOST in microservices (#17659) 2025-04-16 23:05:12 +02:00
Daniel Dietzler 586a7a173b refactor: handle detect faces job query (#17660) 2025-04-16 22:52:54 +02:00
Daniel Dietzler 1bbfacfc09 refactor: more job query stuff (#17658) 2025-04-16 22:10:20 +02:00
Daniel Dietzler 85c2d36d99 refactor: dedicated get album thumbnail files query (#17657) 2025-04-16 21:10:27 +02:00
Jason Rasmussen 8cefa0b84b refactor: migrate some e2e to medium (#17640) 2025-04-16 14:59:08 -04:00
Daniel Dietzler f50e5d006c refactor: dedicated queries for asset jobs (#17652) 2025-04-16 14:08:49 -04:00
renovate[bot] 8f8ff3adc0 fix(deps): update machine-learning (#17610) 2025-04-16 10:56:40 -04:00
Zack Pollard c4c35ed140 fix(ci): images missing correct OCI annotations and PR cache (#17378)
Co-authored-by: secustor <sebastian@poxhofer.at>
2025-04-15 22:31:23 +01:00
Nils Uliczka be2f670d35 fix: skip places that no longer exist in geo import (#17637) 2025-04-15 21:27:47 +00:00
Alex 7efcba2b12 chore(mobile): flutter 3.29.3 (#17638)
* chore(mobile): flutter 3.29.3

* chore(mobile): flutter 3.29.3

* upgrade background_downloader
2025-04-15 21:03:22 +00:00
Paul Puschmann 459c815086 feat(docs): Clarify the usage of immich-cli with Docker (#17595)
Add some explanation how to use the various usage parameters together
with the `immich-cli` in the container.
2025-04-15 20:08:55 +00:00
Alex 36fa61c013 fix(mobile): new loading icon too small (#17636) 2025-04-15 20:08:34 +00:00
Jason Rasmussen 8da5f21fcf refactor: medium tests (#17634) 2025-04-15 15:54:23 -04:00
Jonathan Jogenfors 76db8cf604 refactor(server): remove asset placeholder (#17621)
chore: remove AssetEntityPlaceholder

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-04-15 15:53:49 -04:00
Daniel Dietzler 21becbf1b0 refactor: dedicated query for asset migration job (#17631) 2025-04-15 15:49:15 -04:00
Min Idzelis 26f0ea4cb5 feat: responsive controlbar (#17601) 2025-04-15 14:39:30 -05:00
Alex 19e5a6f68f chore(doc): translation instruction for mobile app (#17629) 2025-04-15 14:31:13 -05:00
shenlong 78f8e23834 fix(mobile): exif not updated on sync (#17633)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-04-15 14:30:58 -05:00
Daniel Dietzler 5bceefce75 refactor: stream assets for thumbnail job (#17623) 2025-04-15 19:53:28 +02:00
Jason Rasmussen b710ad36f3 feat: upgrade kysely (#17630)
* feat: upgrade kysely

* chore: pr feedback
2025-04-15 13:26:56 -04:00
Daniel Dietzler 270d178a2e fix: unsafe cast (#17590) 2025-04-15 11:35:00 -05:00
Daniel Dietzler 309528c807 chore: upgrade package locks (#17626) 2025-04-15 11:34:21 -05:00
Toni 7c422363fb chore(mobile): clear the backup detail view when no backup is in progress (#17619)
Clear the backup detail view when no backup is in progress

* When no backup is in progress, display a simple "-" for the details in the upload file info, instead of the data of the last uploaded asset.
* This prevents confusion if a upload job is stuck or just finished.
2025-04-15 11:30:24 -05:00
Weblate (bot) 3eb316abea chore(web): cleanup unused translations (#17624) 2025-04-15 17:24:29 +01:00
renovate[bot] b3371e16f2 fix(deps): update typescript-projects (#17611)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 15:55:03 +00:00
Alex b2c903c000 feat(mobile): use Weblate for i18n (2) (#17620)
* feat(mobile): use Weblate for i18n (2)

* remove old translation files

* dedup keys

* remove migration report

* chore

* remove localizely.yml
2025-04-15 15:54:26 +00:00
Jason Rasmussen 17e720440d refactor: new asset-job repository (#17622)
* refactor: new asset-job repository

* fix: broken medium tests on main
2025-04-15 10:24:51 -04:00
Alex a522130122 feat(mobile): use Weblate for i18n (1) (#17609) 2025-04-15 08:30:01 -05:00
Weblate (bot) cecd9c24a4 chore(web): update translations (#17438)
Co-authored-by: Alex <rainbowpulp@gmail.com>
Co-authored-by: Andreas Johansen <andreas@josern.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Ciprriann <cipriannebeja@gmail.com>
Co-authored-by: Eskuero <3skuero@gmail.com>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: GiannosOB <giannos2105@gmail.com>
Co-authored-by: Gustavo Batista <gustavo_prg@hotmail.com>
Co-authored-by: Happy <happygamernintendoswitch@gmail.com>
Co-authored-by: Indrek Haav <indrek.haav@hotmail.com>
Co-authored-by: Josep Mengual <josep@truita.es>
Co-authored-by: Leo Bottaro <github@leobottaro.com>
Co-authored-by: Leonard Baki <leonard.baki@gmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Miki Mrvos <medolino2009@gmail.com>
Co-authored-by: Molnar Eduard <edimolnar@posteo.ro>
Co-authored-by: Nergis <me@nergis.dev>
Co-authored-by: Nghiem Long Phan <nghiemlong@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Stein-Aksel Basma <stein-aksel@basma.no>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: TheScientistPT <joao.ed.reis.gomes@gmail.com>
Co-authored-by: User 123456789 <w0g-1es-5qq@cld3.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: alexxss <rainbowpulp+weblate@gmail.com>
Co-authored-by: anton garcias <isaga.percompartir@gmail.com>
Co-authored-by: bittin1ddc447d824349b2 <bittin@reimu.nl>
Co-authored-by: hachimaru <eugenereuh@gmail.com>
Co-authored-by: kylo32 <kylo32@gmail.com>
Co-authored-by: millallo <millallo@tiscali.it>
Co-authored-by: shiuh67 <shiuh.cheng@gmail.com>
Co-authored-by: stelle <itsazripp2@gmail.com>
Co-authored-by: szelek <janek.szelewicz@gmail.com>
Co-authored-by: timmy61109 <qazzxcasdqwewsxedc@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: xuars <yago.rana.gayoso@gmail.com>
2025-04-15 14:27:57 +01:00
Jason Rasmussen f189c7b101 refactor: medium tests (#17599) 2025-04-15 08:53:14 -04:00
renovate[bot] c5f087a3ca chore(deps): update mcr.microsoft.com/devcontainers/typescript-node:22 docker digest to a20b8a3 (#17606)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 12:56:00 +01:00
renovate[bot] 72f6d7791e chore(deps): update dependency @sveltejs/kit to v2.20.6 [security] (#17603)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 12:47:30 +01:00
renovate[bot] f73fce1046 chore(deps): update base-image to v202504081114 (major) (#17613)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 12:47:10 +01:00
renovate[bot] f2edcde1b2 chore(deps): update actions/create-github-app-token action to v2 (#17612)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 12:04:43 +01:00
renovate[bot] 9d0dd9dff8 chore(deps): update github-actions (#17605)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 12:03:45 +01:00
Mert c3d10c5be2 refactor(server): non-nullable file metadata (#17598) 2025-04-15 12:03:31 +01:00
Andrei Mironov bd92748ddd perf(mobile): optimize date loading with batch loading (#17240)
* perf(mobile): optimize date loading with batch loading

Introduce DateBatchLoader to reduce the number of database queries by loading dates in batches, improving performance when querying large lists.

* remove unused totalCount parameter from DateBatchLoader

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-04-14 19:06:36 +00:00
Toni aad5c3bada chore(mobile): don't show drag scroll date in search page (#17594)
Dont show drag scroll date in search page

* When using the drag scroll, the date of the current image is shown. This is now made toggleable.
* For the mobile search result page, the display of the date is now disabled because the results are not sorted by date and therefore a display of the date is not desirable.
2025-04-14 14:03:18 -05:00
Jason Rasmussen b2753103c6 chore: remove unused logger (#17593) 2025-04-14 15:01:49 -04:00
Aamir Azad e3f3baadb0 fix(web): improve mobile web album viewer padding (#17575)
Reduce margin on mobile web album viewer
2025-04-14 13:46:53 -05:00
Daniel Dietzler 0b69d1c147 refactor: selected columns in queries (#17589) 2025-04-14 13:34:06 -05:00
Min Idzelis 5a51ad3622 fix: responsive: timeline glitch and keyboard-accessible scrubber (#17556)
* fix: responsive: timeline glitch

* lint

* fix margin-right on mobile

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-04-14 11:56:40 -05:00
AutisticShark 664c99278a feat(mobile): remove duplicated i18n file (#17591)
https://github.com/immich-app/immich/issues/8946

Co-authored-by: Cat <cat@nextpanel.dev>
2025-04-14 11:36:18 -05:00
Daniel Dietzler 184e142d87 refactor: migrate asset job status entity (#17560) 2025-04-14 12:21:56 +02:00
Andreas Tollkötter 8b00578c7b fix: read longitude and latitude when reverse geocoding is off (#17558) 2025-04-14 10:43:46 +01:00
Erik Nygren 7562088fac feat(server): parse EXIF creation time for some insta360 images (#17564)
It seems insta360 stores metadata in XMP GPano tags, with their own
non-standard and undocumented addition `SourceImageCreateTime`. For some
pictures this is the only EXIF tag containing a creation time.
2025-04-13 23:44:18 -04:00
Ben 79d4ce2d6d fix(web): search bar deactivates when focus exits (#17549)
* fix(web): search bar deactivates when focus exits

* fix: disable search bar on destroy

For example, on the search page. If the escape key is pressed while the advanced filters button is focused, the search page will close but the search bar will remain activated.
2025-04-13 22:43:50 -05:00
Min Idzelis 983f656a6b fix: in dev, delay web server start until api server is started (#17563) 2025-04-13 10:06:35 -04:00
Alex ab2a7006f9 chore(mobile): small visual fix and update (#17547)
* chore(mobile): small visual fix and update

* update

* update

* remove design placeholder
2025-04-13 08:01:32 -05:00
Min Idzelis 1f18fe31f0 fix: occasional empty buckets, after canceled loads (#17552) 2025-04-13 07:50:24 -05:00
Daniel Dietzler a373034629 refactor: migrate stacks (#17559)
chore: migrate stacks
2025-04-12 08:33:35 -04:00
renovate[bot] 5dac315af7 fix(deps): update dependency @nestjs/common to v11.0.16 [security] (#17557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-12 12:31:18 +02:00
Min Idzelis 8309b73a02 fix: responsive: long press while scroll (#17555) 2025-04-11 18:28:36 -04:00
Min Idzelis e440cbe353 feat: responsive-web: shrink mem-lane (#17550) 2025-04-11 17:10:58 -05:00
Daniel Dietzler 5548eb0dad fix: live photo hiding (#17548) 2025-04-11 17:09:58 -05:00
Min Idzelis 3bec8dc337 refactor: responsive: device units (#17551) 2025-04-11 17:09:10 -05:00
Min Idzelis 5bcb58c3e7 feat: responsive: skeleton (#17553)
feature: responsive: skeleton
2025-04-11 17:04:48 -05:00
Min Idzelis c62fc155c8 feat: show thumbhash behind load error, if possible (#17554)
* feat: show thumbhash behind load error, if possible

* forgot this
2025-04-11 17:01:51 -05:00
Rudhra Raveendran 40e3322b25 docs: Add PowerShell example for running web client only (#17546)
Add PowerShell example for running web client only
2025-04-11 17:02:21 -04:00
Mert 25f2b9602f refactor(server): remove face, person and face search entities (#17535)
* remove face, person and face search entities

update tests and mappers

check if face relation exists

update sql

unused imports

* pr feedback

generate sql, remove unused imports
2025-04-11 14:44:45 -04:00
Jason Rasmussen ae6653392e feat: view qr code from share modal (#17544) 2025-04-11 14:02:07 -04:00
Etienne d7a782da34 feat: sync pictureFile with oidc if it isn't set already (#17397)
* feat: sync pictureFile with oidc if it isn't set already

fix: move picture writer to get userId

fix: move await promise to the top of the setPicure function before checking its value and automatically create the user folder

chore: code cleanup

* fix: extension double dot

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-04-11 13:00:39 -05:00
renovate[bot] 08b5952c87 chore(deps): update dependency vite to v6.2.6 [security] (#17541)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-11 13:56:01 -04:00
Jason Rasmussen 584e5894bf refactor: user factories instead of stubs (#17540) 2025-04-11 11:53:37 -04:00
Yaros 52d4b2fe57 fix(mobile): remove locate asset button from trashed asset (#17503)
* fix: remove locate asset button from trashed asset

* chore: refactor code
2025-04-11 09:41:10 -05:00
Ben 92f0973a46 fix(web): reset search history after logout (#17534)
fix(web): reset search suggestions after logout
2025-04-10 20:34:45 +00:00
Jason Rasmussen 75c83cb704 refactor: metadata stub (#17532) 2025-04-10 21:58:55 +02:00
Jason Rasmussen 0b22d3348e refactor: count all return type (#17529) 2025-04-10 14:38:49 -04:00
Alex abde0fbe60 fix(web): mobile view double scroll layer (#17528) 2025-04-10 13:50:05 -04:00
Jason Rasmussen eaa0e07329 refactor: asset files entity (#17527) 2025-04-10 13:26:27 -04:00
Mitchell Pleune 9fd2c5220d fix: test_sets_default_sess_options fails if compiling with globally enabled cuda (#17516)
Coming from nixos, this test fails when cuda is enabled. https://github.com/NixOS/nixpkgs/pull/382896

Solution as proposed by @mertalev
2025-04-10 13:06:33 -04:00
Snowknight26 7fcab4b251 feat(server): read additional lens exif tags (#17125)
* fix(server): read additional lens exif tags

* Update order of read tags

* Fix e2e test

* Fix e2e test

* Fix e2e test

* Fix e2e test

* Update test

* Filter unknown lens exif data

* Formatting fixes
2025-04-10 12:02:41 -05:00
Ben e3995fb5f4 fix(web): increase sidebar breakpoint (#17436) 2025-04-10 12:00:30 -05:00
Alex 6d3f3d8616 refactor: convert download manager into a state class (#17491)
* fix(web): download progress bar not functioning

* remove unused method
2025-04-10 16:48:21 +00:00
Jason Rasmussen 4412680679 refactor: remove unused shared users list (#17526) 2025-04-10 11:44:47 -05:00
Brandon Wees 7df2c9c905 fix: patch-package install in docker build and better postgres patch (#17523)
* always patch package when running npm i, install immich CLI outside of directory so post install doesnt run

* handles case where query is an object and defined but origin is not.

* move patch-package from a dev dependency to a normal dependency. Also copy the patches folder for the docker build to use and patch with

* fix Dockerfile

* use query.reject instead of throw for queryError

* package-lock to reflect the dev dependency change

* dont throw the error, just provide an empty string for query.origin if it does not exist

* remove npm link and demote patch-package back to a dev dependency

* modify patch to add defensive check to catch queries that will fail to parse and reject
2025-04-10 12:43:35 -04:00
Daniel Dietzler 7a1e8ce6d8 chore: remove exif entity (#17499) 2025-04-10 12:36:29 -04:00
Jason Rasmussen 8aea07b750 refactor: album user entity (#17524) 2025-04-10 11:53:21 -04:00
Zack Pollard 94dba29298 refactor: remove user entity (#17498) 2025-04-10 10:53:21 -04:00
Rudhra Raveendran 9e49783e49 feat: use browser download manager for single file downloads (#17507)
* Fix download panel reactivity

* Directly download individual files without buffering in memory

* Fix shared link e2e download tests
2025-04-10 09:13:50 -05:00
renovate[bot] 43e3075f93 fix(deps): update machine-learning (#17455) 2025-04-09 16:20:11 +00:00
Zack Pollard d03647904b refactor: remove move entity (#17489) 2025-04-09 11:54:20 -04:00
Jason Rasmussen 206545356d refactor: metadata entity (#17492) 2025-04-09 11:45:30 -04:00
renovate[bot] 3e372500b0 fix(deps): update typescript-projects (#17456)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-04-09 14:47:29 +00:00
Jason Rasmussen 8943ec23ba refactor: more database types (#17490) 2025-04-09 10:24:38 -04:00
Gagan Yadav 04b03f2924 fix(mobile): asset grid will infinitely scroll on iOS when select and… (#17469)
fix(mobile): asset grid will infinitely scroll on iOS when select and drag
2025-04-09 08:36:27 -05:00
Jason Rasmussen cf2c0260a6 refactor: activity item (#17470)
* refactor: activity item

* fix query

* qualified columns

---------

Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
2025-04-09 08:35:20 -04:00
Alex ae8af84101 fix: no thumbnail generated for motion assets (#17472) 2025-04-08 16:07:10 -05:00
Jason Rasmussen 4794eeca88 refactor: database types (#17468) 2025-04-08 12:40:03 -04:00
Gagan Yadav ac65d46ec6 fix(mobile): adds support for Internationalized Domain Name (IDN) (#17461) 2025-04-08 11:04:42 -05:00
Alex e5ca79dd44 refactor: remove session entity (#17466)
* refactor: remove session entity

* fix: test

* update sql

* remote export
2025-04-08 16:04:07 +00:00
Jason Rasmussen 49be6d7fd8 refactor: more database enums (#17465) 2025-04-08 12:02:05 -04:00
Daniel Dietzler 15c6506aee fix: broken start/end dates on album update (#17467) 2025-04-08 15:47:44 +00:00
Jason Rasmussen 2c31a11e41 chore: replace generated enums with actual types (#17463) 2025-04-08 11:13:46 -04:00
Jason Rasmussen b6c5a03533 refactor: remove tag entity (#17462) 2025-04-08 10:52:54 -04:00
Gagan Yadav 75bc32b47b fix(mobile): hide asset description text field if user is not owner (#17442)
* fix(mobile): hide asset description text field if user is not owner

* If user is not the owner and asset has no description then hide the text field

* Apply suggestions from code review

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

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-04-08 09:18:33 -05:00
Jason Rasmussen fdbe6d649f refactor: remove smart search entity (#17447)
refactor: smart search entity
2025-04-08 09:56:45 -04:00
Aleksandr 2b131fe935 feat: opt-in sync of deletes and restores from web to Android (#16732)
* Features: Local file movement to trash and restoration back to the album added. (Android)

* Comments fixes

* settings button marked as [EXPERIMENTAL]

* _moveToTrashMatchedAssets refactored, moveToTrash renamed.

* fix: bad merge

* Permission check and request for local storage added.

* Permission request added on settings switcher

* Settings button logic changed

* Method channel file_trash moved to BackgroundServicePlugin

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-04-08 08:50:40 -05:00
snek 6ae24fbbd4 feat(web): improve individual share ux (#17430) 2025-04-08 09:11:37 -04:00
renovate[bot] 7f116d8e98 chore(deps): update mcr.microsoft.com/devcontainers/typescript-node:22 docker digest to b0b88ef (#17453)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 13:32:14 +01:00
renovate[bot] bd0840c411 chore(deps): update github/codeql-action digest to 45775bd (#17452)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 13:31:57 +01:00
renovate[bot] a5123dec1a chore(deps): update grafana/grafana docker tag to v11.6.0 (#17460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 13:31:46 +01:00
renovate[bot] ffd18c5459 chore(deps): update dependency @types/node to ^22.14.0 (#17459)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 12:14:30 +02:00
PyKen 8242ff9bab fix(server): Exclude album assets in shared link payload (#17207)
* fix(server): Exclude album assets in shared link payload

* Fix e2e test
2025-04-08 00:19:06 -04:00
Jason Rasmussen 8203b6c450 refactor: stop using geodata entity type (#17444) 2025-04-08 00:15:43 -04:00
Jason Rasmussen b352cf3336 refactor: remove natural earth countries enity (#17445) 2025-04-08 00:15:16 -04:00
bo0tzz 96ed9a8c4a fix: restore mangled footnotes (#17446)
I broke this in #17257
2025-04-07 18:03:32 -04:00
Jason Rasmussen e7a5b96ed0 feat: extension, triggers, functions, comments, parameters management in sql-tools (#17269)
feat: sql-tools extension, triggers, functions, comments, parameters
2025-04-07 15:12:12 -04:00
renovate[bot] 51c2c60231 chore(deps): update dependency vite to v6.2.5 [security] (#17391)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-07 16:35:29 +01:00
shenlong 43d585ce55 fix(mobile): exifInfo not updated on sync (#17407)
* fix(mobile): exifInfo not updated on sync

* add tests

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-04-07 10:21:37 -05:00
shenlong 042da669d1 fix(mobile): use custom filter to fetch asset path entities (#17344)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-04-07 09:39:24 -05:00
Yaros a724f147fe fix(mobile): items not deselecting on back button (#17403)
* fix: items not deselecting on back button

* chore: add comments
2025-04-07 09:35:27 -05:00
Sebastian Schneider 1e4b9ae5b7 fix(mobile): video player restarting when device rotates (#17362)
* fix(mobile): Video player restarting when device rotates

* use global key in state

* Implement suggestions from code review
2025-04-07 09:26:08 -05:00
Ruben Hensen 99cddf1fd6 feat: allow accounts with a quota of 0 GiB (#17413)
* Allow 0GiB quotas in user create/edit form, remove unused translations

* Make requireQuota check for null or 0

* Add unlimited quota change to the docs

* Fix user dto formatting

* Fix formating edit-user-form

* Regenerate open-api files

* Revert unnecessary i18n file changes

* Re-add newline en.json

* Resolve linting issues

* Fix formatting edit-user-form

* Re-add manifest
2025-04-07 09:22:56 -05:00
Weblate (bot) 30d33f968f chore(web): update translations (#17254)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/bg/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/bi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ca/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/cs/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/el/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/et/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fa/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fi/
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/hr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hu/
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/ka/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lv/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ms/
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/ro/
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_Cyrl/
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/ta/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/te/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/th/
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/vi/
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: Bonov <bonov@mail.ru>
Co-authored-by: C D <chinnidiwakar5@gmail.com>
Co-authored-by: Daniel Correa Lobato <daniel@lobato.org>
Co-authored-by: Emre Saraçoğlu <hello@emresaracoglu.com>
Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Co-authored-by: GND <jehende@jehende.fr>
Co-authored-by: Gocha Gulua <gocha.gulua@gmail.com>
Co-authored-by: Hurricane-32 <rodrigorimo@hotmail.com>
Co-authored-by: Indrek Haav <indrek.haav@hotmail.com>
Co-authored-by: Leigh van der merwe <palitu822@gmail.com>
Co-authored-by: LennartWeinzierl <lennart.weinzierl@gmx.de>
Co-authored-by: Leo Bottaro <github@leobottaro.com>
Co-authored-by: Luis Peregrina <luis.a.peregrina@gmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Miki Mrvos <medolino2009@gmail.com>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Oleksandr Zhukov <aleksandr.a.zhukov@gmail.com>
Co-authored-by: Passawish Paktiwong <passawishp@outlook.com>
Co-authored-by: Petri Hämäläinen <petri.hamalainen@mailbox.org>
Co-authored-by: Ruben Hensen <ruben.hensen@protonmail.com>
Co-authored-by: Runskrift <anders@rimfrost.nu>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Stein-Aksel Basma <stein-aksel@basma.no>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: Tachibana Saza <tachibanasaza@proton.me>
Co-authored-by: Temuri Doghonadze <temuri.doghonadze@gmail.com>
Co-authored-by: Theofilos Nikolaou <th.nikolaou@gmail.com>
Co-authored-by: User 123456789 <w0g-1es-5qq@cld3.com>
Co-authored-by: Vin <k3kelm4vw@mozmail.com>
Co-authored-by: aks-cadesign <aks@cadesignbase.dk>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: grgergo <gergo_g@proton.me>
Co-authored-by: late <late@users.noreply.hosted.weblate.org>
Co-authored-by: millallo <millallo@tiscali.it>
Co-authored-by: przmkg <przemek@gasinski.eu>
Co-authored-by: thehijacker <thehijacker@gmail.com>
Co-authored-by: timmy61109 <qazzxcasdqwewsxedc@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: xuars <yago.rana.gayoso@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2025-04-07 12:28:59 +01:00
Ben McCann 31ee19181a chore(web): switch to writable derived one more place (#17399) 2025-04-06 22:05:47 -05:00
shenlong b58a450152 fix(mobile): prevent unnecessary reload on multi user timeline (#17418)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-04-06 22:04:13 -05:00
Zlendy b87ba6865b fix(web): Video memories are played at 100% volume instead of respecting user preference (#17424) 2025-04-06 22:03:19 -05:00
Lorenzo Montanari 565cceb323 docs: fixed a wrong path in CLI docs page (#17369)
docs: fixed a wrong path in CLI page
2025-04-06 22:00:10 -05:00
Matthew Momjian f096dd0cc0 fix(deployment): warning for database on network share (#17412)
Update example.env
2025-04-06 10:09:54 +02:00
Daniel Dietzler a3c3f9cfcb fix: reset memories on logout (#17405) 2025-04-05 13:09:56 -04:00
Mert 7b6a4be30c chore: use valkey (#17396)
use valkey
2025-04-04 17:46:46 -05:00
martin 720189e2c2 fix: improve initial loading time (#17379) 2025-04-04 17:04:52 -04:00
shenlong dfab32c8f2 fix(mobile): ignore invalid store keys (#17370)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-04-03 22:35:50 -05:00
shenlong 60174d662d fix(mobile): bump isar maxSize (#17372) 2025-04-03 21:49:50 -05:00
bo0tzz 8b6a765e12 chore: remove demo box spec from README.md (#17367) 2025-04-03 18:09:29 -04:00
Zack Pollard 2248a38567 fix: missing index and geodata import process uses normal table (#17343)
* chore: add geodata indexes to table definitions

* chore: rename incorrectly name geodata index

* fix: import into geodata places with correct index names
2025-04-03 21:32:33 +01:00
shenlong 97e52c5156 refactor(mobile): device asset entity to use modified time (#17064)
* refactor: device asset entity to use modified time

* chore: cleanup

* refactor: remove album media dependency from hashservice

* refactor: return updated copy of asset

* add hash service tests

* chore: rename hash batch constants

* chore: log the number of assets processed during migration

* chore: more logs

* refactor: use lookup and more tests

* use sort approach

* refactor hash service to use for loop instead

* refactor: rename to getByIds

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-04-03 14:42:35 -05:00
Mert e8b4ac0522 fix(web): use original image if web compatible (#17347)
* use original image if web compatible

* add e2e

* fix shared link handling

* handle redirect in e2e

* fix size not being passed to thumbnail url

* test fullsize in e2e
2025-04-03 09:01:41 -05:00
Alex 548298b0c7 chore: post release tasks (#17341) 2025-04-03 08:47:52 -04:00
Zack Pollard 40cff2893c fix: metadata service init failure should halt server startup (#17356) 2025-04-03 12:35:39 +01:00
Abhinav Valecha b621281351 feat(server): Avoid face match with people born after file creation #4743 (#16918)
* feat(server): Avoid face matching with people born after file creation date (#4743)

* lint

* add medium tests for facial recognition

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-04-02 10:37:26 -05:00
Snowknight26 4336afd6bf fix(web): fix thumbnail hover link position (#16762)
* fix(web): don't show a scrollbar when hovering over the last row of images on the search page

* Format code

* Fix asset selection z-index

* Remove anchor overlay on mouseover

* Fix a test

* Fix merge

* Fix overlays

* fix merge

* fix stack thumbs in asset viewer

* fix dimmed bounds, animation

* lint

---------

Co-authored-by: Min Idzelis <min123@gmail.com>
2025-04-02 10:30:41 -05:00
shenlong 5a456ef277 feat(mobile): sqlite (#16861)
* refactor: user entity

* chore: rebase fixes

* refactor: remove int user Id

* refactor: migrate store userId from int to string

* refactor: rename uid to id

* feat: drift

* pr feedback

* refactor: move common overrides to mixin

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-04-02 08:58:17 -05:00
renovate[bot] 5cb5fcbf62 fix(deps): update machine-learning (#17286) 2025-04-02 03:57:19 +00:00
Alex 95e3b15776 fix(web): padding (#17320) 2025-04-01 23:32:54 -04:00
Ben 50335dc363 fix(web): menu button size (#17321)
Adjusting the menu button size, to match match the other buttons in the navigation bar.
2025-04-01 22:25:17 -05:00
Ben 6e62c09d84 feat(web): expand/collapse sidebar (#16768)
* feat: expand/collapse sidebar

* fix: general PR cleanup

- add skip link unit test
- remove unused tailwind styles
- adjust asset grid spacing
- fix event propogation

* fix: cleaning up event listeners

* fix: purchase modal and button on small screens

* fix: explicit tailwind classes

* fix: no animation on initial page load

* fix: sidebar spacing and reactivity

* chore: reverting changes to icons in nav and account info panel

* fix: remove left margin from the asset grid after merging in new timeline

* chore: extract search-bar changes for a separate PR

* fix: add margin to memories
2025-04-01 21:12:04 -05:00
github-actions 00d3b8d83a chore: version v1.131.3 2025-04-01 22:27:52 +00:00
Mert d911b76c08 fix(server): use stat instead of exifinfo for file date metadata (#17311)
* use stat instead of filecreatedate

* update tests

* unused import
2025-04-01 17:24:07 -05:00
shenlong 502854cee1 fix(server): remove stacks on stack.deleteAll (#17288)
* fix(server): delete all stacks on deleteAll

* remove unnecessary assets update

* generate sql

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-04-01 17:20:43 -05:00
Mert 59e5c82569 fix(server): full-size images not migrated or deleted correctly (#17308)
* fix file path logic

* update tests

* add empty array fallback just in case for now
2025-04-01 18:11:46 -04:00
Daimolean e4b0c00885 fix(web): select all button displays incorrectly (#17305)
* fix(web): select all show incorrectly

* fix: lint

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-04-01 19:00:48 +00:00
Alex 946507231d fix(web): blank locale cause blank timeline to render (#17284)
* fix(web): blank locale cause blank timeline to render

* correct fix

* newline

* pr feedback
2025-04-01 18:58:11 +00:00
Alex 20ba800a50 fix(web): date time change reactivity (#17306)
* fix(web): date time change reactivity

* remove logs
2025-04-01 18:57:53 +00:00
Alex f434e858ed fix(mobile): getAllByRemoteId return all assets on empty arguments value (#17263)
* chore: post release tasks

* fix(mobile): getAllByRemoteId return all assets if ids is empty
2025-04-01 08:59:21 -05:00
bo0tzz 3e03c47fbf fix: strip extra metadata when transcoding (#17297) 2025-04-01 08:58:59 -05:00
github-actions 9aa3850769 chore: version v1.131.2 2025-04-01 11:41:56 +00:00
renovate[bot] 628dcdeebf fix(deps): update typescript-projects (#17294)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-01 10:58:55 +00:00
renovate[bot] 11bfde2aa8 chore(deps): update github-actions (#17282)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-01 11:49:11 +01:00
renovate[bot] 69b1ac47ea fix(deps): update typescript-projects (#17287)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-01 12:32:09 +02:00
renovate[bot] 4f81265694 chore(deps): update dependency @types/node to ^22.13.14 (#17283)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-01 12:30:41 +02:00
renovate[bot] 3428a876c7 chore(deps): update dependency vite to v6.2.4 [security] (#17259)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-01 00:36:54 +01:00
Alex bd822657d3 chore: post release tasks (#17262) 2025-04-01 00:36:18 +01:00
Mert 9e7744a9ab fix(ml): healthcheck (#17274) 2025-03-31 19:23:40 -04:00
github-actions 7729fe80fa chore: version v1.131.1 2025-03-31 20:36:48 +00:00
martin 68e24ad168 fix: posix compliant command (#17264) 2025-03-31 16:35:02 -04:00
Jason Rasmussen 186c573565 fix: missing migration folder broke non-root setups (#17266) 2025-03-31 20:18:13 +00:00
github-actions 5b63b9fc8b chore: version v1.131.0 2025-03-31 18:41:13 +00:00
Eli Gao 5c80e8734b feat: original-sized previews for non-web-friendly images (#14446)
* feat(server): extract full-size previews from RAW images

* feat(web): load fullsize preview for RAW images when zoomed in

* refactor: tweaks for code review

* refactor: rename "converted" preview/assets to "fullsize"

* feat(web/server): fullsize preview for non-web-friendly images

* feat: tweaks for code review

* feat(server): require ASSET_DOWNLOAD premission for fullsize previews

* test: fix types and interfaces

* chore: gen open-api

* feat(server): keep only essential exif in fullsize preview

* chore: regen openapi

* test: revert unnecessary timeout

* feat: move full-size preview config to standalone entry

* feat(i18n): update en texts

* fix: don't return fullsizePath when disabled

* test: full-size previews

* test(web): full-size previews

* chore: make open-api

* feat(server): redirect to preview/original URL when fullsize thumbnail not available

* fix(server): delete fullsize preview image on thumbnail regen after fullsize preview turned off

* refactor(server): AssetRepository.deleteFiles with Kysely

* fix(server): type of MediaRepository.writeExif

* minor simplification

* minor styling changes and condensed wording

* simplify

* chore: reuild open-api

* test(server): fix media.service tests

* test(web): fix photo-viewer test

* fix(server):  use fullsize image when requested

* fix file path extension

* formatting

* use fullsize when zooming back out or when "display original photos" is enabled

* simplify condition

---------

Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
2025-03-31 13:24:28 -04:00
bo0tzz a5093a9434 docs: separate upgrading page (#17257)
* docs: separate upgrading page

* chore: move "setup optional features" into postinstall

* docs: stronger backup warning in postinstall

* chore: link to upgrading page

* docs: reiterate breaking changes in upgrade doc

* chore: fix formatting

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-31 11:43:14 -05:00
Mert 637ad1fdcb docs: minor typo (#17258)
three -> two
2025-03-31 18:34:29 +02:00
Mert 6789c2ac19 feat(ml): better multilingual search with nllb models (#13567) 2025-03-31 11:06:57 -04:00
PathToLife 838a8dd9a6 feat(web): increase album collapse click area (#17213) 2025-03-31 09:45:30 -05:00
Brandon Wees d71c5602c3 fix(server): Postgres error pretty printing (#17204)
* add patch-package to dev dependencies

this allows us to patch upstream packages without waiting for PRs to be merged (or not!). Patch-package does a pretty good job of notifying if upstream does a change to invalidate the patch (its a git patch under the hood).

* Patch implementation of https://github.com/porsager/postgres/pull/944

This PR has not been merged by upstream and helps produce verbose error messages when postgres fails to connect (usually incorrect credentials). This is in contrast to error messages such as

`TypeError: Cannot read properties of undefined (reading 'replace'), stack: TypeError: Cannot read properties of undefined (reading 'replace')`

* have postinstall only run when not installing a global package (such as immich-cli in the Docker build)
2025-03-31 09:34:43 -05:00
Mert 8c50e3e80e feat(server): consider JpgFromRaw2 tag for embedded previews (#17123)
* add jpgfromraw2

* unused catch
2025-03-31 09:17:57 -05:00
Jonathan Jogenfors efcb1129ce fix(server): don't sync null date assets (#17247) 2025-03-31 09:16:53 -05:00
Jonathan Jogenfors faabda4446 fix(server): multiple exclusion patterns (#17221) 2025-03-31 09:16:30 -05:00
Alex b8b2898c87 fix(server): double extension when filename has uppercase extension (#17226)
* fix(server): double extension when filename has uppercase extension

* Proper tests
2025-03-31 09:16:04 -05:00
Ben McCann b25914c2a5 chore: use writable derived in more places (#17248)
chore(web): use writable derived in more places
2025-03-31 09:15:52 -05:00
Zack Pollard d613f15606 test: fix flaky user handle delete check medium test (#17253)
we can't run specifically the handleUserDeleteCheck tests concurrently due to one of the tests modifying the config in the shared database
if run concurrently you can get race conditions where the other tests pick up the change, even with resetting the config in the beforeEach
therefore the test that checks a delete actually happens, fails
there are many ways to solve this, disabling concurrency for the suite, forcing sequential tests for just handleUserDeleteCheck, increasing the delete test deletedAt to more than the custom duration tests deleteDelay
I applied all three of these. You could also force all the user tests to run in their own databases, but that feels overkill
2025-03-31 13:19:57 +01:00
hwang a831876fdc fix: MAX_PARAMETERS_EXCEEDED error during person cleanup job (#17222)
* add batch size in sql delete,fix person cleanup error: ERROR [Microservices:{}] Unable to run job handler (backgroundTask/person-cleanup): Error: MAX_PARAMETERS_EXCEEDED: Max number of parameters (65534) exceeded

* add chunked decorator to delete

* chore: prettier formatting fixes

---------

Co-authored-by: hwang3419 <“hwang.iit@gmail.com”>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-03-31 11:30:56 +00:00
PathToLife 09f4476f97 feat: improve performance for GET /api/album & /api/album/:id (#17124)
* fix(server) optimize number of sql calls for GET /api/albums

remove unnecessary join for getMetadataForIds
remove separate call to getLastUpdatedAssetForAlbumId

* fix(server) remove unnecessary getLastUpdatedAssetForAlbumId call for GET /api/album/:id

also remove getLastUpdatedAssetForAlbumId query as it is no longer referenced

* fix(server): correct lastModifiedAssetTimestamp return type + formatting and typing

* chore(server): address type issue with tests found via npm:check

tests & lint still pass before this commit.
2025-03-31 11:28:41 +00:00
Daniel Dietzler 238c151ac3 chore: finish migrating eslint config files; bump unicorn (#17200) 2025-03-31 12:18:25 +01:00
bo0tzz e4f83680d9 feat: use my.immich.app for externalDomain fallback (#17209)
* feat: use my.immich.app for externalDomain fallback

This is probably more useful than localhost.

* chore: remove port param

* fix: update expected value in tests

* fix: update expected value in e2e
2025-03-31 12:08:41 +01:00
Daniel Dietzler 74f7fd4b53 chore: add language requests from weblate (#17236) 2025-03-31 10:48:41 +01:00
Weblate (bot) f4dbfd856e chore(web): update translations (#17115)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ar/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hu/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ja/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ko/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lv/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sv/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/te/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/uk/
Translation: Immich/immich

Co-authored-by: Abhijeet Viswam <abhijeetviswam@gmail.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: C D <chinnidiwakar5@gmail.com>
Co-authored-by: Henrik Sommerfeld <henrik@sommerfeld.nu>
Co-authored-by: Karsten Dambekalns <karsten@dambekalns.de>
Co-authored-by: Miro Rýzek <miroslav.ryzek@gmail.com>
Co-authored-by: Mohd Nader <mohd.nader@gmail.com>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Nergis <me@nergis.dev>
Co-authored-by: Utkarsh Prajapati <utkarshprap@gmail.com>
Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
Co-authored-by: grgergo <gergo_g@proton.me>
2025-03-31 09:47:08 +00:00
Jason Rasmussen 55a3c30664 feat: kysely migrations (#17198) 2025-03-29 09:26:24 -04:00
renovate[bot] 6fa0cb534a fix(deps): update dependency @opentelemetry/context-async-hooks to v2 (#17031)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-28 20:51:01 +01:00
Ben McCann 9f0dbfc150 chore(web): update to newer persisted store package name (#17094) 2025-03-28 20:40:57 +01:00
Saschl 6419ac74af fix: update renderlist after asset deleted (#16786) 2025-03-28 18:34:19 +00:00
Yaros d2bcf5d716 fix(mobile): pause background video play (#17032)
* fix(mobile): prevent background video playback

* fix: logic for tracking app state

* chore: move lifecycle handler in separate file

* chore: replace useState with useRef

* chore: useOnAppLifecycleStateChange

* fix: removed print statement
2025-03-28 10:32:25 -05:00
shenlong c8331f111f fix(mobile): prefer remote orientation (#17177)
* fix(mobile): prefer remote orientation

* pr feedback

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-28 10:24:31 -05:00
Jason Rasmussen 4b4bcd23f4 feat: schema diff sql tools (#17116) 2025-03-28 10:40:09 -04:00
Ben McCann 3fde5a8328 feat: map globe view, style hot reloading and load lag fixed (#17079)
* chore: upgrade svelte-maplibre and enforce runes

* feat: maplibre-gl 5, globe view, style hot reloading, fast map markers

* fix: remove location-pin class that wasn't being used

---------

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-03-28 14:08:54 +00:00
Joren Guillaume cc3ea32cd2 docs: update folder support for app in README.md (#17191)
Update folder support for app in README.md
2025-03-28 09:35:36 +00:00
Ben McCann 431cf281da chore(web): update typescript-eslint (#17093) 2025-03-28 00:04:31 -04:00
Alex 8f786fd7dd fix(web): form reactivity (#17183) 2025-03-27 19:58:49 -05:00
Alex 3e73765375 fix(web): don't show newly uploaded asset in inapplicable views (#17184) 2025-03-27 19:45:50 -04:00
Alex 411521b21d chore: post release tasks (#17179) 2025-03-27 19:41:22 -04:00
renovate[bot] e163808348 fix(deps): update typescript-projects (#17080)
* fix(deps): update typescript-projects

* fix: otel

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-03-27 22:33:58 +00:00
Ben McCann 411772123f chore(web): remove unused props (#17141) 2025-03-27 23:12:14 +01:00
Mert 84c35e35d6 chore(ml): installable package (#17153)
* app -> immich_ml

* fix test ci

* omit file name

* add new line

* add new line
2025-03-27 19:49:09 +00:00
Mert f7d730eb05 chore(ml): remove exporter (#17182)
* remove exporter code

* update gha
2025-03-27 14:48:02 -04:00
Mert 16e0166d22 docs: evaluate models on xtd-10 and flickr30k (#17159)
update docs
2025-03-27 11:30:51 -05:00
github-actions 43f8f473e9 chore: version v1.130.3 2025-03-27 15:54:30 +00:00
shenlong cc393b2b7b fix(mobile): oauth-mobile-first-login (#17173)
invalidate ref

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-27 15:49:55 +00:00
Alex 6341962de4 fix(web): better touch device detection (#17144)
* fix(web): better touch device detection

* variable name
2025-03-27 10:43:56 -05:00
Min Idzelis c26b28f6a4 fix: bug with svelte gestures (#17154)
* fix: bug with svelte gestures

* lint
2025-03-27 08:51:52 -05:00
shenlong c72c82c401 fix(mobile): faster device album refresh after initial sync (#17170)
fix(mobile): faster device album refresh after fresh sync

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-27 08:47:05 -05:00
Alex fecf3809a6 fix(server): album count does not account for assets without exif (#17150)
* fix(server): album count doesn't accounted for assets without exif

* sql
2025-03-26 21:24:22 -05:00
Mert 619bd72de9 docs: mention rknn among image options (#17156)
mention rknn
2025-03-26 19:05:48 -04:00
Jason Rasmussen fd4a5f71b5 fix: broken album page (#17149) 2025-03-26 18:59:23 -04:00
github-actions 2f8725c66f chore: version v1.130.2 2025-03-26 15:34:54 +00:00
Jonathan Jogenfors 9fbd6369b9 fix(server): check asset against multiple import paths (#17128)
* fix sql logic

* refactor: map import paths into not or sql statements

---------

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-03-26 10:10:53 -05:00
Snowknight26 c547d849d9 fix(web): prevent comb box dropdowns from staying open when clicking on labels (#17119)
fix(web): prevent combobox dropdowns from staying open when clicking on label
2025-03-26 08:58:00 -05:00
renovate[bot] 6ba94ac2f2 fix(deps): update machine-learning (#17078)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 02:04:41 +00:00
Alex dfb0626c91 fix(web): default search to context (#17118)
* fix(web): default search to context

* one liner

* Refactor
2025-03-25 17:57:12 -05:00
Alex 392ce7deb2 fix(web): albums display order again (#17117) 2025-03-25 22:14:00 +00:00
Mert 75df8fc10e refactor(server): bulk update exif (#17109)
* bulk update exif

* update sql

* update tests

* check job queeuing in test
2025-03-25 21:24:24 +00:00
github-actions 4cf7c55680 chore: version v1.130.1 2025-03-25 20:25:01 +00:00
Alex b8ff93a3c9 chore: post release tasks (#17097) 2025-03-25 21:22:30 +01:00
Alex 37eb70c1eb fix(web): albums display order (#17106)
* fix(web): albums display order

* ergonomic

* perf ergonomic

* miss 1
2025-03-25 20:21:38 +00:00
renovate[bot] aa4d6405f4 chore(deps): update base-image to v202503251114 (major) (#17085)
* chore(deps): update base-image to v202503251114

* fix: geocoding changes

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-03-25 20:15:02 +00:00
Alex ae447542a4 fix(web): asset navigation (#17104) 2025-03-25 15:00:30 -05:00
renovate[bot] 90f21d9047 chore(deps): pin dependencies (#17077)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-25 18:07:59 +00:00
renovate[bot] 567a92fe77 chore(deps): update dependency vite to v6.2.3 [security] (#17092)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-25 18:07:25 +00:00
Weblate (bot) 8d6f5a2da9 chore(web): update translations (#16807)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/af/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/cs/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/da/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/el/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/et/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/he/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hu/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/id/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/it/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lv/
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/sk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sr_Cyrl/
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/te/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/th/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/uk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ur/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: -J- <heyj0e@tuta.io>
Co-authored-by: Agostino Pit <scheccia@gmail.com>
Co-authored-by: Andreas Johansen <andreas@josern.com>
Co-authored-by: Andreas Resch <weblate@resch.io>
Co-authored-by: Basilis Pantelis <bpantelis10@gmail.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Bonov <bonov@mail.ru>
Co-authored-by: C D <chinnidiwakar5@gmail.com>
Co-authored-by: Dawider10 <dawider110@gmail.com>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Co-authored-by: Focron <eliaelmas55@gmail.com>
Co-authored-by: Hurricane-32 <rodrigorimo@hotmail.com>
Co-authored-by: Indrek Haav <IndrekHaav@users.noreply.hosted.weblate.org>
Co-authored-by: Jean-Philippe Jodoin <jpjodoin@gmail.com>
Co-authored-by: Johan Ohly <johanohly@gmail.com>
Co-authored-by: Jørgen Næss Berge <jorgen.n.berge@gmail.com>
Co-authored-by: KecskeTech <teonyitas@gmail.com>
Co-authored-by: Knud Bachmann Røn <knudbachmannron@proton.me>
Co-authored-by: Leo Bottaro <github@leobottaro.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: MSDNicrosoft <wang3311835119@hotmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Miki Mrvos <medolino2009@gmail.com>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Nicolás McCarthy <nicomcc24@gmail.com>
Co-authored-by: Runskrift <anders@rimfrost.nu>
Co-authored-by: Ryan Gleeson <gleeson.ryanj@gmail.com>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: Tomas Svec <svec.tomas@gmail.com>
Co-authored-by: Umesh Verma <umesh.verma236@gmail.com>
Co-authored-by: User 123456789 <w0g-1es-5qq@cld3.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: beckett <beckett.blakey@proton.me>
Co-authored-by: johnwoo_nl <pb@lunenburg-productions.nl>
Co-authored-by: millallo <millallo@tiscali.it>
Co-authored-by: pyccl <changcongliang@163.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: xuars <yago.rana.gayoso@gmail.com>
Co-authored-by: yousaf465 <yousaf465@gmail.com>
Co-authored-by: 灯笼 <gh_denglong@163.com>
2025-03-25 18:05:23 +00:00
bo0tzz 69662e1ab4 chore: shared renovate configuration (#16903)
* chore: shared renovate configuration

dep: https://github.com/immich-app/.github/pull/2

* chore: move typescript-projects and schedule to shared config

---------

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-03-25 14:56:54 +00:00
github-actions 42b1efb679 chore: version v1.130.0 2025-03-25 13:48:45 +00:00
Snowknight26 b8bc11b0d9 fix(web): fix escape key not closing video player after seeking (#16860)
Co-authored-by: Yaros <thedj.launchpadder.dmx512@gmail.com>
2025-03-25 13:42:23 +00:00
Ben McCann 91065db3ff chore: migrate previously missed file to Svelte 5 (#17074) 2025-03-24 19:44:05 -04:00
Alex c14668bdd4 chore(mobile): translation (#17073)
chore(mobile): translation update
2025-03-24 22:16:10 +00:00
Yaros 9757f70064 fix(web): not autoplay after moving playhead on paused video (#17038)
fix(web): prevent autoplay after moving playhead
2025-03-24 16:55:46 -05:00
Min Idzelis 4a0045db44 feat(web): support long-press selection on mobile web (#16906)
* feat(web): max grid row height responsive

* also gallery-viewer

* lint

* feat(web): support long-press selection on mobile web

* use svelte-gestures

* fix test

* Bug fix

* globalThis

* format

* revert generator

* Testing

* bad merge

* Fix typo/tap on thumbnail

* feat: shrink header on small screens (#16909)

* feat(web): shrink header on small screens

* fix test

* test

* Fix test

* Revert user-page-layout chagne

* Restore icons sizes, make consistent, improve logo responsiveness

* remove 4 more pix, lint

* lint

* chore

---------

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

* Revert "Testing"

This reverts commit 442f11c9e1.

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-03-24 16:36:36 -05:00
Yaros a651a4bf0e chore(mobile): search field in separate widget (#16977)
* chore(mobile): search field in separate widget

* fix: removed unnecessary use of context

* chore: minor styling tweak

* fix: controller not bound

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-24 14:40:33 -05:00
Alex 8bc80076bb fix(mobile): show new local assets in offline mode (#16817)
fix: show new local assets in offline mode
2025-03-24 16:56:18 +00:00
Luigi311 89656472ef fix(mobile): fallback authentication client model/type to unknown (#17059)
mobile: fallback authentication client model/type to unknown

Add fallback for client model/type if device is not ios or android

Signed-off-by: Luis Garcia <git@luigi311.com>
2025-03-24 11:26:05 -05:00
Yaros d9c6ec06e5 chore(mobile): suffix to app name on debug builds (#17044) 2025-03-24 11:23:07 -05:00
Mert 4bfef2460a docs: model benchmarks (#17036)
* model benchmarks

* minor fixes

* formatting

* docs build

* maybe fix reference

* clarify optimal

* use emojis

* wording

* wording

* clarify optimal wording

* bolding

* more detailed instructions

* clarify edge case fix

* early exit in dim loop
2025-03-24 12:02:33 -04:00
shenlong ad151130f9 chore: rename user api interface (#17062)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-24 11:00:08 -05:00
Damiano Ferrari a77608e36b fix(mobile): selectedIcon not set when the device is landscape (#17027) 2025-03-24 10:50:49 -05:00
Nicholas Flamy 9e015c7f97 feat: lint workflow files and others files in .github (#16914)
* add npm prettier dep and format script to .github folder

* initial work on prettier formatting test

* attempt index notation

* change name of .github job to be valid

* another use of index notation

this is getting overcomplicated

* Change job ID to `github-files-formatting` and chane the name to `.github Files Checks`

* Change job name to `.github Files Formatting`

* Update Makefile with .github module and `filter-out`s

* run prettier formatting as added in this PR
2025-03-24 10:49:18 -05:00
Damiano Ferrari df8ba21b7d fix(mobile): Make icons consistent (all outlined) (#17028)
* fix(mobile): Make icons consistent (all outlined)

* fix(mobile): make `date_range` icon outlined
2025-03-24 10:10:15 -05:00
Yaros a285b1898e fix(mobile): platform-dependent share icons & label (#17034)
fix: platform-dependant icons
2025-03-24 08:36:15 -05:00
Mert 6a8e38042d fix(ml): add librknnrt.so in rknn image (#17022)
add librknnrt.so
2025-03-21 16:57:14 -04:00
Min Idzelis 55b52ecbec feat: mobile-web improvements - scrubber (#16856)
* feat: mobile-web improvements - scrubber

* lint

* cruft

* lint

* fix: thumb style

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-03-21 18:00:24 +00:00
Alex b5d5c40c69 fix(web): update stack state in timeline (#17021)
* fix(web): update stack state in timeline

* js docs

* fix: handle state update from unstack action from gallery viewer

* use navigate in View Stack notification

---------

Co-authored-by: Snowknight26 <Snowknight26@users.noreply.github.com>
2025-03-21 12:42:36 -05:00
Snowknight26 b00da18e84 fix(web): timeline renders nothing with an invalid asset scroll target (#16994)
* fix(web): fix asset grid showing nothing with an invalid asset target

* Deduplicate

* Scroll to position where appropriate

* a bit cleaner

* fix: lint

---------

Co-authored-by: Min Idzelis <min123@gmail.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-21 08:40:57 -05:00
Ben 3c87341902 fix(web): clicking away closes context menu (#16989)
* fix(web): clicking away closes context menu

* fix: use pointerdown event instead

* Revert "fix: use pointerdown event instead"

This reverts commit 0d2cf47194.
2025-03-21 08:39:41 -05:00
Alex bcd9248b43 fix(web): timeline regression 2 (#16982)
* fix(web): timeline renders nothing after archiving in asset viewer

* fix(web): timeline renders nothing after archiving in asset viewer

* fix: ensure geometry updated when performing bulk action on all

* fix: album assets selection
2025-03-20 22:30:27 -05:00
Alex dbc279f843 fix: gallery viewer sliding window offload assets (#17016)
* fix: gallery viewer sliding window offload assets

* fix: update bottom sliding window

* do not use negative

* Calculate offset before gallery

---------

Co-authored-by: Min Idzelis <min123@gmail.com>
2025-03-20 22:30:01 -05:00
Alex 21954939cf chore: remove limit in memory generation (#16920)
* chore: remove limit in memory generation

* generate sql

* chore: assets limit
2025-03-20 13:31:51 -05:00
renovate[bot] d537f2c2d1 chore(deps): update github-actions (#16965)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-20 13:17:36 -05:00
Snowknight26 1820c0aa0d fix(web): fix View in Timeline not working for stacked assets (#16993)
Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
2025-03-20 13:17:14 -05:00
Yaros 0d805a1f5b fix(web): removed merge person with itself (#16987)
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-20 15:25:42 +00:00
Alex f5e6042eb1 fix: extend e2e test cookie expiration date (#17007)
fix: extend e2e test cookie
2025-03-20 16:17:55 +01:00
renovate[bot] 8de71ddaf3 chore(deps): update dependency flutter to v3.29.2 (#16963)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-19 10:58:57 -05:00
Min Idzelis 7075c5b393 feat(web): make asset grid row height responsive (#16970)
* feat(web): max grid row height responsive

* also gallery-viewer

* lint
2025-03-19 10:57:44 -05:00
Min Idzelis 9398b0d4b3 fix: regression in select-all (#16969)
* bug: select-all

* set->[] in interaction store, clear select-all on cancel

* feedback

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-03-19 15:55:50 +00:00
renovate[bot] 1a0a9ef36c chore(deps): update base-image to v202503182202 (major) (#16968)
chore(deps): update base-image to v202503182202

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-19 00:28:32 -04:00
Dmitry Vakhnenko ce456709b5 fix(web): reset selection state when adding assets to a album (#16880)
* fix(web): cancel multiselect before adding assets to album

* chore: format with prettier

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-19 00:11:58 +00:00
renovate[bot] bc90678276 fix(deps): update machine-learning (#16966) 2025-03-18 23:07:21 +00:00
renovate[bot] 217a90bf61 chore(deps): update actions/download-artifact digest to b14cf4c (#16934)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 17:10:19 -05:00
Yaros 62ba8c3e71 fix(web): date alignment on timeline (#16961) 2025-03-18 21:55:36 +00:00
renovate[bot] 564724b398 fix(deps): update machine-learning (#16960)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 20:55:43 +00:00
renovate[bot] cedeba8723 chore(deps): update prom/prometheus docker digest to 502ad90 (#16956)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 16:48:52 -04:00
bo0tzz 1d994333a6 fix: duplicated steps in docker workflow (#16952)
Not sure how that happened, maybe a bad merge conflict resolution?
2025-03-18 16:39:30 -04:00
renovate[bot] db8155f738 fix(deps): update typescript-projects (#16945)
* fix(deps): update typescript-projects

* fix: very weird variables

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-03-18 20:29:21 +00:00
renovate[bot] 4d723f4b56 chore(deps): update dependency types-setuptools to v76 (#16949)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 15:02:25 -04:00
renovate[bot] 898b3e75c2 fix(deps): update machine-learning (#16935)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 17:09:46 +00:00
bo0tzz 8c2d02c362 chore: run docs and cli builds on all PRs (#16954)
All the other workflows already do this.
2025-03-18 11:55:18 -05:00
Dmitry Vakhnenko d7a6e78bf0 fix(server): /api/stacks does not handles primaryAssetId query param (#16868)
fix(server): add missing validation decorator
2025-03-18 11:54:50 -05:00
Viharm 8723f585e0 chore(docs): clarify missing ':ro' tag in volume mount as a warning (#16877)
📝 Clarify missing ':ro' tag in volume mount as a warning

Changed description in comment of example docker compose file to clarify it as a warning that Immich may delete it, instead of sounding as if it is ok to delete.

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-18 16:50:59 +00:00
Mert 9f46ba8eb4 fix(server): set pixel format when scaling and not tonemapping (#16932)
set pixel format when scaling and not tonemapping
2025-03-18 11:42:09 -05:00
Andreas fe19f9ba84 fix(web): asset selection on memories page is broken (#16759)
* 16712: Proper intialisation of the memory store to avoid loading up duplicate object refs of the same asset.

* 16712: Add auth to memory mapping so isFavorite is actually return correctly from the server.

* 16712: Move logic that belongs in the store into the store.

* 16712: Cleanup.

* 16712: Fix init behaviour.

* 16712: Add comment.

* 16712: Make method private.

* 16712: Fix import.

* 16712: Fix format.

* 16712: Cleaner if/else and fix typo.

* fix: icon size mismatch

* 16712: Fixed up state machine managing memory playback:
* Updated to `Tween` (`tweened` was deprecated)
* Removed `resetPromise`. Setting progressController to 0 had the same effect, so not really sure why it was there?
* Removed the many duplicate places the `handleAction` method was called. Now we just called it on `afterNavigate` as well as when `galleryInView` or `$isViewing` state changes.

* 16712: Add aria tag.

* 16712: Fix memory player duplicate invocation bugs. Now we should only call 'reset' and 'play' once, after navigate/page load. This should hopefully fix all the various bugs around playback.

* 16712: Cleanup

* 16712: Cleanup

* 16712: Cleanup

* 16712: Cleanup

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-03-18 11:34:09 -05:00
renovate[bot] b609f35841 chore(deps): update base-image to v20250318 (major) (#16950)
* chore(deps): update base-image to v20250318

* chore

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-18 11:07:11 -05:00
shenlong 9cf3b88f80 refactor(mobile): remove int user id (#16814)
* refactor: user entity

* chore: rebase fixes

* refactor: remove int user Id

* refactor: migrate store userId from int to string

* refactor: rename uid to id

* fix: migration

* pr feedback

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-18 11:05:37 -05:00
Min Idzelis e96ffd43e7 feat: timeline performance (#16446)
* Squash - feature complete

* remove need to init assetstore

* More optimizations. No need to init. Fix tests

* lint

* add missing selector for e2e

* e2e selectors again

* Update: fully reactive store, some transitions, bugfixes

* merge fallout

* Test fallout

* safari quirk

* security

* lint

* lint

* Bug fixes

* lint/format

* accidental commit

* lock

* null check, more throttle

* revert long duration

* Fix intersection bounds

* Fix bugs in intersection calculation

* lint, tweak scrubber ui a tiny bit

* bugfix - deselecting asset doesnt work

* fix not loading bucket, scroll off-by-1 error, jsdoc, naming
2025-03-18 09:14:46 -05:00
shenlong dd263b010c refactor(mobile): use user service methods (#16783)
* refactor: user entity

* chore: rebase fixes

* refactor(mobile): refactor to use user service methods

* fix: late init error

* fix: lint

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-18 08:32:33 -05:00
renovate[bot] 6c2985df26 chore(deps): update dependency @types/node to ^22.13.10 (#16944)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 12:15:07 +01:00
Mert 2b37caba03 feat(ml): rocm (#16613)
* feat(ml): introduce support of onnxruntime-rocm for AMD GPU

* try mutex for algo cache

use OrtMutex

* bump versions, run on mich

use 3.12

use 1.19.2

* acquire lock before any changes can be made

guard algo benchmark results

mark mutex as mutable

re-add /bin/sh (?)

use 3.10

use 6.1.2

* use composite cache key

1.19.2

fix variable name

fix variable reference

aaaaaaaaaaaaaaaaaaaa

* bump deps

* disable algo caching

* fix gha

* try ubuntu runner

* actually fix the gha

* update patch

* skip mimalloc preload for rocm

* increase build threads

* increase timeout for rocm

* Revert "increase timeout for rocm"

This reverts commit 2c4452f5d132198ed381a7b262b4a5cab5114b5f.

* attempt migraphx

* set migraphx_home

* Revert "set migraphx_home"

This reverts commit c121d3e48754b3bce100636f8d666deec58a44b7.

* Revert "attempt migraphx"

This reverts commit 521f9fb72dbe506dc6cb8faeb6494817d87265c6.

* migraphx, take two

* bump rocm

* allow cpu

* try only targeting migraphx

* skip tests

* migraph 

* known issues

* target gfx900 and gfx1102

* mention `HSA_USE_SVM`

* update lock

* set device id for rocm

---------

Co-authored-by: Mehdi GHESH <mehdi.ghesh@hotmail.fr>
2025-03-17 21:08:19 +00:00
Jason Rasmussen 6a40aa83b7 refactor: better types for getList and getDeletedAfter (#16926) 2025-03-17 15:32:12 -04:00
Yaros 93907a89d8 fix(mobile): age calculation & formatting (#16833) 2025-03-17 13:51:17 -05:00
renovate[bot] 3ce8608662 chore(deps): update mcr.microsoft.com/devcontainers/typescript-node:22 docker digest to 2ef2373 (#16925)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 14:07:09 -04:00
Abhinav Valecha d0e283f687 feat(server): version command for immich-admin #9611 (#16924)
* feat(server): Add version command for immich-admin #9611

* chore: clean up

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-03-17 17:57:59 +00:00
Yaros f8b40188e2 fix(mobile): change share icons for consistency (#16904) 2025-03-17 12:34:58 -05:00
renovate[bot] 9105e696bf chore(deps): pin github action dependencies (#16923)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 17:25:14 +00:00
bo0tzz 0a8135dde4 fix: docker workflow for rknn (#16922)
* fix: specify gha runner for rknn

* fix: remove s from platforms

* fix: merge job for rknn
2025-03-17 18:13:43 +01:00
Jason Rasmussen 0bb95544e5 chore: pin github action digests (#16875) 2025-03-17 11:30:13 -05:00
Yoni Yang 14c3b99c0f feat(ml): ML on Rockchip NPUs (#15241) 2025-03-17 12:04:08 -04:00
shenlong 1e184a70f1 refactor: cleanup background service (#16855)
refactor: background service

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-17 08:48:22 -05:00
Jason Rasmussen 9a4495eb5b refactor: use more immich ui buttons (#16840) 2025-03-14 09:38:06 -04:00
Jason Rasmussen 8ad95b368b feat: use immich ui components for dialog component (#16839) 2025-03-14 09:37:56 -04:00
shenlong b778a86c99 refactor(mobile): move user service to domain (#16782)
* refactor: user entity

* chore: rebase fixes

* refactor(mobile): move user service to domain

* fix: timeline not visible on album selection page

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-13 22:20:26 -05:00
Jason Rasmussen a65ce2ac55 refactor: immich logo assets (#16850) 2025-03-13 18:05:08 -04:00
Jason Rasmussen f69d7e7bad chore: web cleanup (#16849) 2025-03-13 18:04:21 -04:00
ExceptionsOccur 858d1e9d9b fix(mobile): back gesture in asset selection page from an album (#16449)
* fix(mobile): the page for adding photos to the album cannot be navigated back using gestures #16409

* First-time return gesture adds the feature to cancel all current selections

---------

Co-authored-by: ExceptionsOccur <yuyu.tao@foxmail.com>
2025-03-13 11:37:05 +05:30
renovate[bot] a1a61f19eb chore(deps): update typescript-projects (#16795)
* chore(deps): update typescript-projects

* fix: aria

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-03-12 23:20:26 +01:00
Jason Rasmussen 996ffed5eb fix: immich ui toggles and switches (#16834)
* fix: immich ui toggles and switches

* Update web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte

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

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-12 16:25:27 -05:00
Jason Rasmussen 2d7a94ce23 feat: better library rename UX (#16837) 2025-03-12 16:00:16 -05:00
Jason Rasmussen 72a7be26c0 refactor: use immich/ui button component in user settings (#16836) 2025-03-12 15:56:55 -05:00
shenlong 77fad86b82 chore(mobile): bump dependency versions (#16823)
* chore(mobile): bump dep version

* reorganize files

* sort

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-12 14:33:11 +00:00
Yaros 52d90a8280 fix(web): fixed formatting of video length (#16829)
* fix(web): fixed formatting of video time

* shortened the condition
2025-03-12 09:18:43 -05:00
shenlong d1c8fe5303 refactor: user entity (#16655)
* refactor: user entity

* fix: add users to album & user profile url

* chore: rebase fixes

* generate files

* fix(mobile): timeline not reset on login

* fix: test stub

* refactor: rename user model (#16813)

* refactor: rename user model

* simplify import

---------

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

* chore: generate files

* fix: use getAllAccessible instead of getAll

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-12 08:56:56 -05:00
Snowknight26 a75718ce99 fix(web): update search results when searching from info panel (#16729)
* fix(web): update search results when searching from info panel

* Prevent double search when using search bar

* Format/lint

* Fix infinite loading on intersect

* Remove redundant function
2025-03-11 17:23:25 -05:00
Nicholas Flamy d72d715f6b fix(docs): logo not loading dark theme variant in production (#16820)
fix logo not loading dark theme variant in production
2025-03-11 17:13:25 -05:00
Jason Rasmussen 16fd19994b refactor: use factory and kysely types for partner repository (#16812) 2025-03-11 16:29:56 -04:00
Mert 83ed03920e fix(ml): dev environment dependencies (#16815)
use /opt/venv
2025-03-11 13:39:33 -05:00
bo0tzz 9c825e15de fix: run preview label remove job on PR close (#16811)
🤦
2025-03-11 15:26:09 +00:00
Andreas b8acae2f21 feat(web): Add keyboard shortcut selection on grid (#16713)
* 15712: Added keyboard shortcuts for opening add to album modal and highlighting/selecting an album to add to.

* 15712: Re-factored logic from template code into script. Extracted new album button into separate cmponent.

* 15712: Document new keyboard shortucts now that they work everywhere.

* 15712: Extract some constants/helper functions.

* 15712: Missing comma.

* 15712: Pulled logic out into separate unit testable class.

* 15712: Added a unit test.

* 15712: Move the modal back up to keep the github PR happy.

* 15712: PR feedback - renamed typescript files and switch to class bind directive.

* 15712:Move selection modal into correct package.

* 15712: Better naming of module and files.

* 15712: Add asset highlight using arrow keys.

* 15172: Add escape behaviour everywhere.

* 15712: Don't allow highlighting past start or end.

* 15712: Clear the highlight on changes to the component state.

* 15712: Use focus to track highlighted element.

* 15712: Rename highlight -> focussed.

* 15712: Better naming.

* 15712: Cleanup.

* 15712: Cleanup & simplify.

* 15712: bugfix for clicking on button.

* 15712: Cleanup.

* 15712: Rollback unnecessary changes.

* 15712: Add unit test.

* 15712: Add thumbnail unit test.

* 15712: Prettier.

* 15712: Fix merge issue.

* 15712: Add shortcut info.

* 15712: Fix linter.
2025-03-11 10:18:14 -05:00
Alex c80afea468 feat(web): better person naming interface (#16631)
* feat(web): better person naming interface

* feat(web): better person naming interface

* feat(web): better person naming interface

* feat(web): better person naming interface

* feat(web): better person naming interface

* feat(web): better person naming interface

* feat(web): better person naming interface
2025-03-11 10:08:52 -05:00
shenlong 6caa11d079 chore(mobile): use path provider foundation (#16804)
* chore(mobile): use path provider foundation

* chore: update podfile

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-11 09:26:43 -05:00
shenlong 653fa3f0b1 chore(mobile): add orientation tests for exif (#16806)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-11 09:25:46 -05:00
Alex 2be8b6c16d chore: ignore correct build folder (#16808) 2025-03-11 14:22:05 +00:00
Jonathan Jogenfors 6bb0aa217c fix(server): set unit test timezone to UTC (#16805) 2025-03-11 10:19:33 -04:00
bo0tzz 04fd83d9da chore: shared suffix for docker tags (#16727) 2025-03-11 12:25:10 +00:00
renovate[bot] ba9e3715f0 chore(deps): update base-image to v20250311 (major) (#16803)
chore(deps): update base-image to v20250311

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-11 12:24:31 +00:00
shenlong ac1b2d2fab chore(mobile): generated files and ci check (#16798)
* chore(mobile): more generated files

* ci: verify generated files in mobile are up-to-date

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-11 12:22:31 +00:00
Lorenzo Montanari d7e0f0e70e feat(web): exposed a job to manually trigger database backup procedures (#16622)
* feat(web): exposed a new job to create a manual database backup

* chore(server): added a new test case

* chore(server): moved job to backup db into the create job popup

* remove irrelevant change

* openapi

* chore: formatting

* docs: trigger backup documentation

---------

Co-authored-by: Lorenzo Montanari <13736036+l0ll098@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
Co-authored-by: Zack Pollard <zack@futo.org>
2025-03-11 11:30:43 +00:00
Snowknight26 decc878267 feat(web): show full date when hovering over photos date groups (#16561)
* fix(web): Update asset grid date group titles to show full date

* Fix formatting
2025-03-11 11:18:29 +00:00
Zack Pollard e0a09f2ea0 fix: weblate pre-job not running (#16802)
* chore: add debug step to weblate pre-job

* fix: weblate enforce lock missing needs for pre-job
2025-03-11 11:10:00 +00:00
sarunas-zilinskas b9ecdf9286 chore: change k which stood for 1000 to more understandable notation of kbit/s (#16734) 2025-03-11 10:54:42 +00:00
Weblate (bot) 4c719cc3bb chore(web): update translations (#16252)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/af/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ar/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/bg/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ca/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/cs/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/da/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/el/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/et/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/he/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hu/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/id/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/it/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ko/
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/nn/
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/sk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sr_Cyrl/
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/th/
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/ur/
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: -J- <heyj0e@tuta.io>
Co-authored-by: Ahmad Amin <ahmadamindev@gmail.com>
Co-authored-by: Andreas Johansen <andreas@josern.com>
Co-authored-by: Aniruddha <aniruddha@aniruddhas.com>
Co-authored-by: Bader Alqahtani <baq100@gmail.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Björn Boström <weblate@boztrom.com>
Co-authored-by: Bonov <bonov@mail.ru>
Co-authored-by: Bora Atıcı <boratici.acc@gmail.com>
Co-authored-by: Carlo_Mava <carlomavaracchio@gmail.com>
Co-authored-by: Cem TURKER <forumcemturker@gmail.com>
Co-authored-by: Cohinem <twitch9ofe@gmail.com>
Co-authored-by: ConfusedAlex <alex@confusedalex.dev>
Co-authored-by: Damian Krysta <damian@krysta.dev>
Co-authored-by: Daniel A <aquino.daniel1994@ikmail.com>
Co-authored-by: Eric Lehmann Llevat <lemmi93@googlemail.com>
Co-authored-by: Eskuero <3skuero@gmail.com>
Co-authored-by: Etienne-Bdt <etienne.bardet@gmail.com>
Co-authored-by: FarSniper <ozmatlik@gmail.com>
Co-authored-by: Felipe Simões <felipebouabci@gmail.com>
Co-authored-by: Filip <fjokovic0@gmail.com>
Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Georgi Iliev <georgi.iliev533@outlook.com>
Co-authored-by: Hoi <Hoihoi@users.noreply.hosted.weblate.org>
Co-authored-by: Hurricane-32 <rodrigorimo@hotmail.com>
Co-authored-by: Héctor Martínez Juste <hectorzin@hotmail.com>
Co-authored-by: Indrek Haav <IndrekHaav@users.noreply.hosted.weblate.org>
Co-authored-by: JohannesBoanerges <jb@johannes-boanerges.de>
Co-authored-by: Jonathan Jogenfors <jonathan@jogenfors.se>
Co-authored-by: Jordy H <jordy@hoebergen.net>
Co-authored-by: Juan Palacios <mastergeek.juan@gmail.com>
Co-authored-by: Julius969 <juliusdjorup@proton.me>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Leo Bottaro <github@leobottaro.com>
Co-authored-by: Leonardo Patti <leonardo.patti90@gmail.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Macgyver <macgyver@users.noreply.hosted.weblate.org>
Co-authored-by: MaliciousSpark <fijalkowskikonras@gmail.com>
Co-authored-by: Marius Kavoliunas <kavoliunas.m@gmail.com>
Co-authored-by: Mateusz <account.srrr3@slmail.me>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Medallyon <mbups98@gmail.com>
Co-authored-by: Miki Mrvos <medolino2009@gmail.com>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Nir Cohen <nir10146@gmail.com>
Co-authored-by: PPNplus <ppnplus@protonmail.com>
Co-authored-by: Pavol Valko <xpaulos2@gmail.com>
Co-authored-by: Philipp Burndorfer <phi.bur@gmx.at>
Co-authored-by: Pixiii <imapixel00@gmail.com>
Co-authored-by: Runskrift <anders@rimfrost.nu>
Co-authored-by: Sandro <account@donner-nsu.de>
Co-authored-by: Santiago <santiwever@hotmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Sheridan Jegels <sheridanjegels@gmail.com>
Co-authored-by: Stijn <gielisstijn@gmail.com>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: Toine Rademacher <hi@toine.zip>
Co-authored-by: Torin Wu <xuan329269@gmail.com>
Co-authored-by: Vesa Jylhä <vesa.jylha@gmail.com>
Co-authored-by: Vladimir <vladimir.stoev1015@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: Yaros <thedj.launchpadder.dmx512@gmail.com>
Co-authored-by: anton garcias <isaga.percompartir@gmail.com>
Co-authored-by: atsza661 <ats.altmets@gmail.com>
Co-authored-by: chamdim <chamdim@protonmail.com>
Co-authored-by: chapvic <victor@chapaev.org>
Co-authored-by: francesco stigliano <fra.stigliano@gmail.com>
Co-authored-by: icerocker <icerocker@users.noreply.hosted.weblate.org>
Co-authored-by: mattix7771 <mattione7@gmail.com>
Co-authored-by: pierrebengtsson <pierre.bengtsson@gmail.com>
Co-authored-by: pyccl <changcongliang@163.com>
Co-authored-by: qtm <qtm@users.noreply.hosted.weblate.org>
Co-authored-by: szelek <janek.szelewicz@gmail.com>
Co-authored-by: thehijacker <thehijacker@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: xuars <yago.rana.gayoso@gmail.com>
Co-authored-by: Øyvind Hovden <oyvhov@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2025-03-11 10:48:34 +00:00
shenlong 81df812f56 fix(mobile): calculate isFlipped for exif from db (#16797)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-11 10:41:47 +00:00
Nicholas Flamy f0f0056fe3 feat(docs): highlight active version in version switcher (#16790)
* docs: highlight active version in version switcher

* Add comment explaining workaround
2025-03-11 10:41:12 +00:00
renovate[bot] 48dddb78d4 chore(deps): update docker/setup-qemu-action action to v3.6.0 (#16794)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-11 10:37:36 +00:00
Nicholas Flamy 5d86e6d2d3 fix(web): update old discord logo to new one (#16789)
* fix: update discord svg path and add viewbox

* fix formatting
2025-03-10 22:46:32 -05:00
Alex 75fa305e98 chore: flutter 3.29.1 (#16730)
* update dependencies

* update flutter version reference

* update flutter version reference

* update AndroidManifest with flutter_web_auth_2

* chore: lock file flutter version

* fix: ios build
2025-03-10 21:46:36 -05:00
renovate[bot] 8cd5aec4c5 chore(deps): update dependency @types/node to ^22.13.9 (#16792)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-10 22:43:16 -04:00
renovate[bot] cb489a1aa9 chore(deps): pin ghcr.io/astral-sh/uv docker tag to 562193a (#16791) 2025-03-10 22:23:50 -04:00
Jason Rasmussen 1382b27349 refactor: repository mocks (#16785) 2025-03-10 16:52:44 -04:00
Jason Rasmussen 1b35400043 chore: remove unused package (#16777) 2025-03-10 14:50:32 -04:00
Jason Rasmussen a96bba4b26 feat: sync assets, partner assets, exif, and partner exif (#16658)
* feat: sync assets, partner assets, exif, and partner exif

Co-authored-by: Zack Pollard <zack@futo.org>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>

* refactor: remove duplicate where clause and orderBy statements in sync queries

* fix: asset deletes not filtering by ownerId

---------

Co-authored-by: Zack Pollard <zack@futo.org>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-03-10 12:05:39 -04:00
Jason Rasmussen e97df503f2 refactor: api key spec to use factories (#16776) 2025-03-10 12:04:35 -04:00
renovate[bot] fe959b2f05 fix(deps): update machine-learning (#16594) 2025-03-10 14:48:53 +00:00
Yaros f794c3e0df feat(web): show birthdate on person page (#16772)
* feat(web): show birthdate on person page

* shorten null check

Co-authored-by: Jason Rasmussen <jason@rasm.me>

* directly use birthDate

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-10 14:47:44 +00:00
Alex 57272904d6 chore(mobile): upgrade maplibre (#16739)
* chore(mobile): upgrade maplibre

* chore(mobile): upgrade maplibre

* color
2025-03-10 09:41:43 -05:00
Jensen H 2496bd7514 docs: update unraid installation steps (#16766)
Update unraid.md

Current steps omit this key step, which results in the postgresql docker complaining about the data folder not being empty. (It tries to use the `/mnt/user/appdata` folder as its application data folder.
2025-03-10 08:56:42 +00:00
Nicholas Flamy c6ede48e59 fix(server): set the dev server restart policy of the dev server container to match the other containers (#16753)
set the restart policy of the dev server container to match the other containers
2025-03-09 22:25:03 -05:00
Adam O'neill 70a08707d2 feat(web): remember search context (#16614)
* Retain search context in LocalStorage.

* Remove debug logging

* Prettier

* Added QueryType and VALID_QUERY_TYPES to $lib/constants

* Prettier

* Renamed VALID_QUERY_TYPES to fit the codestyle.

Ran prettier

* show current search type on search bar

* fix: linting

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-03-09 22:20:25 -05:00
Snowknight26 2f8e89c7ec feat(server): read Android and Sony video camera make/model (#16678)
* feat(server): read Android and Sony video camera exif data

* Remove a logger line
2025-03-09 22:20:11 -05:00
David Bourgault 9870ad9687 fix(server): adjust type of person.birthDate (#16628)
The API currently does not respect the documentation when returning a
person's birthDate. The doc/swagger says it will be of "YYYY-MM-DD"
format but the string is a full ISO8601-with-tz string. This causes
issue #16216 because the <input> tag is strict about supported value
formats.

I believe this was introduced by #15242 which switched some queries from
TypeORM to Kysely for the person repository. TypeORM does not parse
date, but our Kysely configuration does (explicitely).

This commits updates the types to represent both possibilities and ensure
the API always returns the correct format.
2025-03-09 21:32:05 -05:00
Lukas 097749d872 fix(web): add labels to memory lane buttons (#16664)
* fix(web): add labels to memory lane buttons

* use generic button labels
2025-03-09 21:31:55 -05:00
Yaros bdabea4030 feat(mobile): locate in timeline (#16722)
* feat(mobile): view in timeline

* fix: throwing error on scroll

* only show option if not in photos tab
2025-03-09 21:31:34 -05:00
Mert 6da77600e5 chore(ml): uv (#16725)
* poetry to uv

* update ci

* remove caching

* add typeshed to dev

* no need for `--non-interactive`

* move backends to extras

* oopsie

* update ci
2025-03-09 21:30:16 -05:00
Daniel Dietzler 573d9a7733 fix: 🍪 packages confusion (#16735)
fix: cookie packages confusion
2025-03-09 21:03:10 -05:00
Corentin Hatte 2aac679185 fix(web): Update people-card favorite position (#16746)
Update people-card favorite position

Move heart icon a bit more inward to mak it more visible
2025-03-10 01:32:32 +00:00
Alex 82624b0979 chore(mobile): upgrade riverpod (#16742) 2025-03-09 20:30:58 -05:00
Alex 17c5094719 chore(mobile): upgrade flutter_web_auth_2 (#16741)
* chore(mobile): upgrade flutter_web_auth_2

* pod file
2025-03-09 20:26:37 -05:00
Matthew Momjian 051431b757 fix(docs): edge case when restoring dump that is unreadable as current user (#16758)
* new gunzip setup

* windows
2025-03-09 20:26:00 -05:00
Yaros 6c5f99c47a feat(mobile): person age on photo properties (#16728)
* feat(mobile): person age on photo properties

* switch to using placeholder
2025-03-08 23:02:40 +01:00
Jason Rasmussen 1e127ae3a1 refactor: migrate library spec to factories (#16711) 2025-03-08 13:44:36 -05:00
Jason Rasmussen fd46d43726 chore: remove unused file (#16707) 2025-03-07 22:47:27 -06:00
Yaros 5252c013ec fix(mobile): fix notification icon not displaying properly (#16710) 2025-03-07 19:08:53 -06:00
Jason Rasmussen 3f06a494a9 refactor: queue asset deletes via stream (#16706) 2025-03-07 22:22:57 +00:00
renovate[bot] 086d8a448a fix(deps): update typescript-projects (#16597)
* fix(deps): update typescript-projects

* chore: update server lock file

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-03-07 21:20:45 +00:00
bo0tzz 8ace44fb95 feat: log before running migrations (#16703)
* feat: log before running migrations

* fix: it's called log not info

It should be called info...

* chore: fix formatting

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-07 21:15:06 +00:00
Jason Rasmussen ce74f765b1 refactor: memory stub (#16704) 2025-03-07 16:03:34 -05:00
Yaros b0bf4e4fff feat(mobile): search on people page (#16696) 2025-03-07 14:43:32 -06:00
Jason Rasmussen 2d106755f6 refactor: convert activity stub to a factory (#16702) 2025-03-07 15:20:04 -05:00
Jason Rasmussen f82786a297 feat: use stream for template migrations (#16700) 2025-03-07 14:30:01 -05:00
Yaros c12986d38c fix(mobile): remain on albums tab after album deletion (#16698)
fix(mobile): remain on albums after album deletion
2025-03-07 13:25:07 -06:00
Matthew Momjian 19c40e3be9 fix(docs): remove /api from README (#16692)
* no api

* change internationalized
2025-03-07 08:58:18 -05:00
Jonathan Jogenfors 9959755dda refactor(server): use constant for external library batch size (#16685) 2025-03-07 11:29:06 +00:00
Lukas fdf2331c82 fix(web): hide scroll right button when scrolled to the right in memory lane (#16656)
fix(web): hide scroll right button when scrolled to the right
2025-03-06 20:50:56 -06:00
Lukas e03d7f888e fix(web): remove margin on last memory item (#16665) 2025-03-07 02:50:16 +00:00
Matthew Momjian 2eeed6524f fix(github): consistent folder format for PR template (#16669)
consistent formatting for folders
2025-03-06 20:32:10 -05:00
Jason Rasmussen d45fa491ce refactor: stream asset ids for library queue jobs (#16666) 2025-03-06 20:22:17 -05:00
Matthew Momjian 5c82c485d7 feat(server): normalize extensions in storage template (#16667)
* normalize and lowercase extensions

* un const

* do not change ext before stripping off old one

* braces
2025-03-06 18:02:28 -05:00
Sergey Katsubo feb65bf5a7 docs: reading existing face tag metadata is supported currently (#16662)
Fix FAQ: reading existing face tag metadata is supported currently
2025-03-06 20:42:14 +00:00
Jason Rasmussen 2cdbb0a37c refactor: database repository (#16593)
* refactor: database repository

* fix error reindex check

* chore: remove WIP code

---------

Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
2025-03-06 13:33:24 -05:00
shenlong fe931faf17 refactor: exif entity (#16621)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-06 11:58:24 -06:00
Arno 4ebc25c754 feat(mobile): Folder View for mobile (#15047)
* very rough prototype for folder navigation without assets

* fix: refactored data model and tried to implement asset loading

* fix: openapi generator shadowing query param in /view/folder

* add simple alphanumeric sorting for folders

* basic asset viewing in folders

* rudimentary switch sorting order

* fixed reactivity when toggling sort order

* Fixed trailing comma

* Fixed bad merge conflict resolution

* Regenerated open-api

* Added rudimentary breadcrumbs

* Fixed linting problems

* feat: cleanup

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-06 17:27:43 +00:00
Mert deb399ea15 refactor(server): use exiftool for file date metadata (#16453)
* use exiftool for file date metadata

* handle tag not existing in exifinfo (?)

* update medium tests

* fix typo

* set file size too

* set file size only if undefined
2025-03-06 16:47:12 +00:00
Yaros d01b7a0d67 feat(web): aspect ratio of memory cards (#16652)
Fix aspect ratio of memory cards
2025-03-06 15:24:01 +00:00
Jonathan Jogenfors 3af26ee94a feat(server): library refresh go brrr (#14456)
* feat: brr

---------
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
2025-03-06 16:00:18 +01:00
Mert bc61497461 refactor(server): group async calls in metadata extraction (#16450)
* group async calls

use debugFn

no need to change mock

* check call count in tests
2025-03-06 08:56:35 -06:00
Alex 1ed1a0a1fc feat(mobile): new sync (#16556)
* feat(mobile): new sync

* refactor

* refactor

* refactor

* refactor

* refactor

* refactor

* update analysis option

* remove database operation

* pr feedback
2025-03-06 08:44:28 -06:00
Lukas 2875303b4c feat(web): allow horizontal scrolling in memory lane (#16647) 2025-03-06 08:37:11 -06:00
rrrockey d84009648e refactor(server): replace switch statement in sendFile with Record lookup (#16630)
* refactor cache control handling in server/utils/file.ts

* add ability to null CacheControl.NONE

* Cache control handling comment

* Added comment to file.ts

This comment provides a better understanding of what the cacheControlHeader is doing.

* Update file.ts

Added comments

* Update server/src/utils/file.ts

* fix comments in file.ts

* run prettier with --write to fix formatting

---------

Co-authored-by: pnleguizamo <pnleguizamo@gmail.com>
Co-authored-by: drew-kearns <dkearns@iastate.edu>
Co-authored-by: Sierra (Izumi) Brown <119357873+SierraIBrown@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-06 12:46:37 +01:00
Nick Huang fc2df05190 docs: fix png extension typo in supported formats table (#16636)
Update supported-formats.md
2025-03-06 11:44:06 +00:00
Savely Krasovsky 69b5365965 feat: enable PMTiles protocol support (#16629)
This patch enables PMTiles protocol for MapLibre-GL. Protocol allows to fetch tiles from a single file.  This drastically simplifies the process to self-host own tiles.
2025-03-06 10:50:14 +00:00
Alex c110c9b00e chore(mobile): post release task (#16623) 2025-03-05 14:54:56 -06:00
Yaros b241a80339 feat(mobile): Navigate back on memories (#16545)
* Navigate back on memories

* Fixes crash on navigating back
2025-03-05 14:42:43 -06:00
github-actions 31dd15ce8a chore: version v1.129.0 2025-03-05 19:47:50 +00:00
Alex 6108587c8b fix(web): show tags timeline (#16617)
* fix(web): show tags timeline

* fix(web): show tags timeline
2025-03-05 13:36:56 -06:00
Alex 3e50f668d9 feat(mobile): add catalan i18n (#16616)
* feat(mobile): Add Catalan

* refactor

* fix: load correct file

* chore: remove unused language files
2025-03-05 11:47:31 -06:00
Daniel Dietzler 9b82617e22 docs: 60k stars! (#16618)
60k stars! 
2025-03-05 11:40:45 -06:00
Alex 76cb32d8d0 chore(mobile): translations update (#16615)
chore(mobile): translation update
2025-03-05 16:33:41 +00:00
Yaros e8f3348833 fix(mobile): Fixed zh-Hans not persisting (#16608)
Fixed zh-Hans not persisting
2025-03-05 09:56:00 -06:00
Zack Pollard 9922c8de59 fix: storage template failure after re-upload and previous fail (#16611)
fix: storage template breaks when files are re-uploaded after a move failure
2025-03-05 15:00:37 +00:00
shenlong 3f4bbab4eb fix: isar crash on resume from app detach (#16599)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-05 08:28:40 -06:00
Jason Rasmussen 2da9e3152b refactor: download service (#16600) 2025-03-05 08:38:23 -05:00
Min Idzelis 56b85f7479 fix(web): fix lost scrollpos on deep link to timeline asset, scrub stop (#16305)
* Work in progress - super quick asset store->state

* bugfix: deep linking to timeline, on scrub stop

* format, remove stale

* disable test, todo: fix test

* remove unused import

* Fix merge

* lint

* lint

* lint

* Default to non-wasm layout

* lint

* intobs fix

* fix rejected promise

* Review comments, static import wasm

* Back to dynamic

* try top-level-await

* back to the first solution, with more finesse

* comment out wasm for now

* back out the wasm/thumbhash/thumbnail changes

* lint

* Fully remove wasm

* lockfile

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-03-04 20:34:53 -06:00
waclaw66 8b43066632 fix(mobile): .well-known usage (#16577)
fix: .well-known

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-03-04 20:25:57 -06:00
bo0tzz 20acdcd884 chore: run docker workflow on non-main PRs (#16582) 2025-03-05 02:15:17 +00:00
Jonathan Jogenfors 22d348beca feat(server): e2e for missing jobs (#15910)
* feat: test face detection

* Add duplicate and smart search fixes and tests

* do e2e instead

* Remove ML e2e jobs
2025-03-04 20:44:31 -05:00
shenlong 3b0af1c8a9 fix(mobile): do not pause audio on app start (#16596)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-04 16:00:01 -06:00
Mert 61c8237a4d fix(ml): set face detection threshold correctly in locust (#13419)
* set minScore correctly

* cleanup

* remove outdated tag score
2025-03-04 20:52:07 +00:00
Jason Rasmussen d740f0283a chore: no more immortal PRs (#16595) 2025-03-04 15:06:41 -05:00
Jonathan Jogenfors 4ada28ac99 fix(server): check updateLibraryIndex for zero (#16585)
* fix(server): check updateLibraryIndex for zero

* Update web/src/routes/admin/library-management/+page.svelte

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-03-04 20:00:10 +00:00
Jason Rasmussen 63c01b78e2 refactor: test utils (#16588) 2025-03-04 16:15:41 +00:00
renovate[bot] 1423cfd53c chore(deps): update ghcr.io/immich-app/base-server-dev docker tag to v20250304 (#16580)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 15:39:34 +00:00
Snowknight26 867eec86f5 fix(web): Update menu titles to be more consistent (#16558) 2025-03-04 12:55:54 +00:00
Alex 86e8effd8e fix(mobile): incorrect memories with timezone (#16562) 2025-03-04 12:54:54 +00:00
Jonathan Jogenfors 49d393216a fix(server): fix import path truthiness check (#16570) 2025-03-04 12:54:12 +00:00
renovate[bot] 75c9f63757 chore(deps): update typescript-projects (#16573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 12:53:28 +00:00
Kofi 63984890df docs: clean up environment variables formatting & grammar (#16555)
docs: clean up environment variables formatting & grammar - Just going through the docs and noticed some inconsistent capitalization and minor grammar issues. Fixed them up while having my Monday coffee :) Nothing major, but makes the docs a bit more polished.
2025-03-04 05:00:27 +00:00
Jason Rasmussen 1356468c38 fix: reset/regenerate memories (#16548)
fix: reset memories
2025-03-03 23:48:05 -05:00
renovate[bot] c23c53bf6f fix(deps): update machine-learning (#16560) 2025-03-04 01:42:35 +00:00
renovate[bot] 0dcfc43461 chore(deps): update node (#16538)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 14:31:34 -05:00
Jason Rasmussen d1fd0076cc refactor: migration tag repository to kysely (#16398) 2025-03-03 18:41:19 +00:00
Zack Pollard ff19502035 feat: qr code for new shared link (#16543) 2025-03-03 13:40:41 -05:00
renovate[bot] 6ef069b537 chore(deps): update github-actions (#16539)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 18:39:15 +00:00
Matthew Momjian a03e999bde fix(docs): info on preloading ML models (#16452)
info on preload
2025-03-03 18:39:02 +00:00
aviv926 ad1ba4be5f docs: better facial recognition cluster guide (#14911)
* Better Facial Recognition Clusters

* Add information about the guide

* Update docs/docs/features/facial-recognition.md

Co-authored-by: Felix Bühler <Stunkymonkey@users.noreply.github.com>

* PR Feedback

---------

Co-authored-by: Felix Bühler <Stunkymonkey@users.noreply.github.com>
2025-03-03 18:33:32 +00:00
Alessandro Baroni f89e74181b fix(web): delete action closes asset viewer in asset view (#15469)
fixes #14647
2025-03-03 18:24:37 +00:00
Eli Gao e2c34f17ba feat(cli): watch paths for auto uploading daemon (#14923)
* feat(cli): watch paths for auto uploading daemon

* chore: update package-lock

* test(cli): Batcher util calss

* feat(cli): expose batcher params from startWatch()

* test(cli): startWatch() for `--watch`

* refactor(cli): more reliable watcher

* feat(cli): disable progress bar on --no-progress or --watch

* fix(cli): extensions match when upload with watch

* feat(cli): basic logs without progress on upload

* feat(cli): hide progress in uploadFiles()

* refactor(cli): use promise-based setTimeout() instead of hand crafted sleep()

* refactor(cli): unexport UPLOAD_WATCH consts

* refactor(cli): rename fsWatchListener() to onFile()

* test(cli): prefix dot to mocked getSupportedMediaTypes()

* test(cli): add tests for ignored patterns/ unsupported exts

* refactor(cli): minor changes for code reviews

* feat(cli): disable onFile logs when progress bar is enabled
2025-03-03 13:05:32 -05:00
Zack Pollard 23b1256592 ci: weblate checks should always run, should skip on en.json (#16544) 2025-03-03 17:12:26 +00:00
Yaros 7bbc1d9f68 feat(web): Video memories on web (#16500)
* Video memories on web

* switched mixed up strings
2025-03-03 09:54:26 -06:00
renovate[bot] 8b24c31d20 fix(deps): update typescript-projects (#16540)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 09:38:24 -06:00
shenlong 7f61ac6983 chore(mobile): fix store.put type def (#16517)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-03 09:11:13 -06:00
shenlong 4db8f0c666 refactor(mobile): move timeline methods to timeline repo (#16526)
* refactor: move timeline calls to timeline repo

* refactor: review changes

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-03 09:10:09 -06:00
renovate[bot] 3d6a6f77a8 chore(deps): update dependency eslint-plugin-svelte to v3 (#16532)
* chore(deps): update dependency eslint-plugin-svelte to v3

* chore: linting

* chore: rebase

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-03-03 14:24:26 +00:00
Mert 5698f446f7 refactor(server): link live photos as part of metadata extraction instead of queueing job (#16390)
* link live photos helper instead of job

* update test

* queue storage template migration

* queue in onDone

* remove link live photos job
2025-03-03 09:19:36 -05:00
renovate[bot] eb74fafb00 chore(deps): update dependency globals to v16 (#16534)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 14:11:44 +00:00
Zack Pollard 24da25dbbf ci: don't check weblate lock on chore/translations and add success job (#16533) 2025-03-03 13:22:33 +01:00
renovate[bot] 9b842d4cca chore(deps): update tensorchord/pgvecto-rs:pg14-v0.2.0 docker digest to 739cdd6 (#16530)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 12:13:38 +00:00
renovate[bot] a99bd94717 fix(deps): update dependency ua-parser-js to v2 (#14301)
* fix(deps): update dependency ua-parser-js to v2

* fix: breaking changes from ua-parsed-js major update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-03-03 12:01:40 +00:00
renovate[bot] 4b568dcbb3 chore(deps): update dependency black to v25 (#16033)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 11:57:46 +00:00
renovate[bot] 12ab56c885 chore(deps): update prom/prometheus docker digest to 6927e09 (#16529)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 11:52:22 +00:00
renovate[bot] eed6465b41 chore(deps): update grafana/grafana docker tag to v11.5.2 (#16301)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 11:51:44 +00:00
renovate[bot] 5f6c16080b chore(deps): update docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0 docker digest to 739cdd6 (#16528)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 11:51:13 +00:00
Alex a2aab1f373 fix: don't use public keyword in migration query (#16514)
Co-authored-by: Zack Pollard <zack@futo.org>
2025-03-03 11:40:14 +00:00
bo0tzz 8e076ecfe4 feat: weblate checks workflow (#16251) 2025-03-03 11:39:53 +00:00
Zack Pollard fe702ba6d7 feat: partner sync (#16424)
feat: partner CUD sync
2025-03-03 11:05:30 +00:00
Jonathan Jogenfors 869839f642 feat(server): library cleanup from ui (#16226)
* feat(server,web): scan all libraries from frontend

* feat(server,web): scan all libraries from frontend

* Add button text
2025-03-02 21:29:02 -06:00
Justin Cichra 8885e3105e chore: reword backup_manual_in_progress (#16513)
fix(i18n): reword backup_manual_in_progress

Split "sometime" into "some time".
2025-03-03 03:27:20 +00:00
bo0tzz 6e51c4ec71 chore: add extra note to no-dupes checkbox (#16499) 2025-03-02 21:02:36 -06:00
knechtandreas 6bf2e8dbcb feat: add album keyboard shortcuts (#16442)
* 15712: Added keyboard shortcuts for opening add to album modal and highlighting/selecting an album to add to.

* 15712: Re-factored logic from template code into script. Extracted new album button into separate cmponent.

* 15712: Document new keyboard shortucts now that they work everywhere.

* 15712: Extract some constants/helper functions.

* 15712: Missing comma.

* 15712: Pulled logic out into separate unit testable class.

* 15712: Added a unit test.

* 15712: Move the modal back up to keep the github PR happy.

* 15712: PR feedback - renamed typescript files and switch to class bind directive.

* 15712:Move selection modal into correct package.

* 15712: Better naming of module and files.
2025-03-02 13:15:00 +00:00
Yaros 366f23774a fix(web): Default to context search on web (#16485)
Default to context search on web
2025-03-02 13:06:15 +00:00
Yaros fd5e931617 fix(mobile): Updated formatting of server address in networking (#16483)
* Updated formatting of server address in networking

* fallback for undefined endpoint
2025-03-02 06:58:05 -06:00
shenlong d8d87bb565 chore(mobile): rename log enum to lowercase (#16476)
* chore(mobile): rename log enum to lowercase

* chore(mobile): do not abbreviate

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-03-02 06:30:48 -06:00
Lukas Jost 6cc1978b2d fix(web): Open huggingface.co link on settings page in new tab (#16470)
fix(web): Open huggingface on settings page in new tab
2025-03-01 23:02:56 +00:00
luzpaz 506d2d0f81 fix(web): fix typos (#16466)
Found via codespell
2025-03-01 16:51:50 -06:00
Yaros f13d13b2ea fix(web): Fixed people list overflowing in advanced search (#16457)
* Fixed people list overflowing in search

* styling: better fix

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-03-01 20:34:57 +00:00
Thomas Laroche 2510684bf7 fix(web): unable to download live photo as anonymous user (#16455) 2025-03-01 14:07:19 -06:00
luzpaz c8eef5ad4d fix(mobile): fix typos (#16456)
Found via codespell
2025-03-01 20:06:47 +00:00
bo0tzz 0cb3dc6211 chore: add 'not duplicate' checkbox to issue template (#16462) 2025-03-01 14:05:36 -06:00
Alex f11080cc2d chore(mobile): post release task (#16437) 2025-02-28 21:09:09 -06:00
Matthew Momjian efcf773ea0 feat(server): Shortened asset ID in storage template (#16433)
* Update storage-template.service.ts

* Update supported-variables-panel.svelte

* docs example

* Update storage-template-settings.svelte
2025-02-28 16:04:34 -05:00
github-actions dc143046e3 chore: version v1.128.0 2025-02-28 18:54:08 +00:00
Jason Rasmussen e684062569 fix: memories off by one (#16434) 2025-02-28 12:51:28 -06:00
Desmond Cox 5c0538e52c fix(server): stringify error log parameter to ensure correct overload (#16422)
* fix(server): stringify error log parameter to ensure correct overload

The intended error(message, stack, context) overload is only selected if context is a string.

* formatter
2025-02-28 11:50:00 -06:00
Jason Rasmussen 84cf0d1670 fix: duplicate memories (#16432) 2025-02-28 17:49:29 +00:00
Jonathan Jogenfors bfcde05b1c chore(server): trash e2e cleanup (#16423) 2025-02-28 12:45:30 -05:00
Mert b3b15e9b61 fix(server): include deleted assets if searching offline assets (#16417)
include deleted assets if searching for offline assets
2025-02-28 09:23:18 -06:00
Zack Pollard 819e56d9ca fix: user delete sync query sort by id (#16420) 2025-02-28 09:22:36 -06:00
shenlong 9a98712db7 fix(mobile): background backup failing due to store (#16418)
fix: background backup failing due to store

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-02-28 07:38:51 -06:00
Alex a185e06399 fix(server): follow logs level setting (#16415) 2025-02-28 00:35:48 -05:00
Calum Dingwall f2be9f7ad1 fix(web): person favorite icon bad placement (#16412)
move favorite person icon to top left

fixes #16003

Co-authored-by: Calum Dingwall <caburum@users.noreply.github.com>
2025-02-27 22:15:37 -06:00
Alex 5c879acd5b fix(server): don't show assets that no longer associate with a face (#16404) 2025-02-27 17:02:00 -06:00
shenlong 28c664c769 refactor(mobile): log service (#16383)
refactor: log service

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-02-27 15:18:49 -05:00
Jason Rasmussen fbd85a89e0 refactor: logger (#16393) 2025-02-27 14:59:50 -05:00
Alex 1c86293035 chore(mobile): update analysis option (#16396)
chore-update-analysis-option
2025-02-27 18:35:28 +00:00
shenlong 4a9d80298b fix(mobile): bootstrap store inside isolates (#16392)
fix: bootstrap store inside isolates

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-27 18:01:36 +00:00
Alex 362feb1e62 feat(web): face tagging dialog enhancement (#16395) 2025-02-27 11:49:07 -06:00
Etienne 5503bf7a60 fix: improve contrast on disabled input field in light mode (#16368) (#16382) 2025-02-27 17:20:03 +00:00
Jonathan Jogenfors d20e2e268a fix(server): don't reimport files more than once (#16375)
* fix(server) don't reimport files more than once

* fix: test

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-02-27 16:45:16 +00:00
Mert a708649504 fix(server): skip stacked assets in duplicate detection (#16380)
* skip stacked assets in duplicate detection

* update sql

* handle stacking after duplicate detection runs
2025-02-27 10:16:13 -06:00
Tom Graham a808b8610e fix(server): Fix delay with multiple ml servers (#16284)
* Prospective fix for ensuring that known active ML servers are used to reduce search delay.

* Added some logging and renamed backoff const.

* Fix lint issues.

* Update to use env vars for timeouts and updated documentation and strings.

* Fix docs.

* Make counter logic clearer.

* Minor readability improvements.

* Extract  skipUrl logic per feedback, and change log to verbose.

* Make code harder to read.
2025-02-27 10:14:09 -06:00
Alex c70c9067b0 refactor(mobile): backup provider (#16360)
* refactor(mobile): backup provider

* refactor(mobile): backup provider
2025-02-27 09:56:23 -06:00
Alex 082471dfd9 chore(mobile): post release task (#16349) 2025-02-27 09:46:34 -06:00
Alex 9a098b4658 fix(web): storage template incorrect example (#16367) 2025-02-27 09:46:20 -06:00
immich-tofu[bot] 9d705097e8 chore: modify .github/FUNDING.yml 2025-02-27 14:28:08 +00:00
Mert 6050485ad8 feat(server): set exiftool process count (#16388)
exiftool concurrency control
2025-02-27 09:24:40 -05:00
Zack Pollard fb907d707d refactor: use new updateId column for user CUD sync (#16384) 2025-02-27 09:22:02 -05:00
Mert 7d6cfd09e6 fix(server): don't expose source types in face creation api (#16381)
* don't expose source types in face creation api

* update open-api

* remove source type reference from web
2025-02-27 17:17:07 +03:00
Zack Pollard 967c69317b feat: updateId uuidv7 column for all entities with updatedAt (#16353) 2025-02-27 12:55:22 +00:00
Curtis Lowder 128d653fc6 fix(web): update search modal to not jump around (#16308)
* fix(web): update search modal to not jump around

Search People selection will change size while loading. This causes the
search modal to jump around as the people load in.

* loading spinner size

* remove unsued code

---------

Co-authored-by: cwlowder <me@curtislowder.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-02-27 03:06:41 +00:00
David Bourgault 8b69114924 feat(web): remember last chosen map location when editing (#16366)
Uses a global store to remember the last location chosen by a user when
editing asset locations. This fixes an annoyance when adding location
data to multiple assets in a row and having to zoom in the same area
everytime.
2025-02-26 21:01:29 -06:00
David Bourgault 4b55888d16 fix: ensure manually tagged faces have proper source type (#16364)
immich-app/immich#16062 added manual face tagging and deletion, but did
not add a new 'SourceType'. The create faces would default to
'machine-learning' which is incorrect, and has the annoying downside
that they will be wiped when the 'Refresh Faces' job is run.

Handling of non-machine-learning faces was previously added in
immich-app/immich#6455. This PR simply extends it to the new manually
tagged faces.
2025-02-26 20:53:21 -06:00
Alex 8fbd650483 refactor(mobile): refactor user provider (#16358) 2025-02-26 17:04:43 -06:00
Alex c778516ce2 fix(web): tag people in video (#16351) 2025-02-26 12:55:32 -06:00
Adam O'neill 2969e25ff7 fix: websockets calling on_new_release across all sessions upon new websocket connection. (#16339)
* Implemented possible fix for the new_release window re-appearing across all active sessions when a new websocket connection is established.

* Reverted websocket.ts

Changes not needed to websocket.ts - was bouncing between ideas, current implementation doesn't need this to change.

* Prettier test format.

* Spelling (Aknowledged --> Acknowledged)
2025-02-26 17:48:18 +00:00
luzpaz c055e1aefe docs: fix typos (#16352)
Found via `codespell -q 3 -S "./i18n,./docs/package-lock.json,./readme_i18n,./mobile/assets/i18n" -L afterall,nd,renderd`
2025-02-26 17:21:27 +00:00
github-actions 5f7f88ff17 chore: version v1.127.0 2025-02-26 15:18:50 +00:00
Zack Pollard 5053130e35 fix: sync set ack validation (#16320) 2025-02-26 09:35:51 -05:00
Alex 4ef7eb56a3 fix(server): memory assets order (#16325) 2025-02-25 19:10:52 -06:00
Alex 8ecc67a364 feat(mobile): use memories api (#16329) 2025-02-25 19:10:31 -06:00
Alex 90f7c3d9ae chore(mobile): translations update (#16328)
chore(mobile): translation update
2025-02-25 15:06:40 -06:00
Alex d0381fddec refactor(mobile): render list (#16303)
* refactor(mobile): render list 2

* wip

* wip: asset selection page

* remove render_list provider

* remove dead code

* yaml format

* remove unused file

* woop woop more clean up

* woop woop more clean up 2

* fix: album selection doesn't load instantly
2025-02-25 11:33:48 -06:00
Jason Rasmussen 7c851893b4 feat: medium tests for user and sync service (#16304)
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-02-25 16:31:07 +00:00
RoseyWasTaken ae61ea7984 Update community-guides.tsx (#16316)
* Update community-guides.tsx

Added an additional card linking to a remote access guide

* Update docs/src/components/community-guides.tsx

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-25 15:52:07 +00:00
Alex bbcaee82f0 chore(web): revert wasm new justify layout (#16277)
* Revert "fix(web): justify layout import (#16267) "

This reverts commit ec58e1065f.

* Revert "fix(web): dynamically import wasm module (#16261)"

This reverts commit 4376fd72b7.

* Revert "feat(web): use wasm for justified layout calculation (#15524)"

This reverts commit 3925445de8.

* Revert "fix(web): viewport reactivity, off-screen thumbhashes being rendered (#15435)"

This reverts commit 52f21fb331.
2025-02-25 09:39:56 -06:00
Nicholas Flamy 16266c9f5a docs: #15988 follow-up: Use URL constructor to fix Version Switcher URL double slash issue (#16014)
* concat location properties and use URL constructor to fix issues

* remove slashes from old version urls

* remove versions 1.125.0 and 1.125.4 that don't have docs archives
2025-02-25 09:34:46 -06:00
Alex 6c64a6dab8 chore(web): Revert slight fade in animation when open/close asset-viewer (#16262) (#16306)
Revert "feat(web): slight fade in animation when open/close asset-viewer (#16262)"

This reverts commit 57829cee26.
2025-02-25 09:27:34 -06:00
ExceptionsOccur c0fe98fe27 feat(mobile): photos group by date in album page view (#16272)
* feat(mobile): photos group by date in album page view

* fix: format

---------

Co-authored-by: ExceptionsOccur <yuyu.tao@foxmail.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-25 15:10:08 +00:00
Alex 579321251f refactor(mobile): partners provider (#16299)
* refactor(mobile): partners provider

* update analysis option

* update analysis option
2025-02-25 08:52:33 -06:00
Nicholas Flamy 392f9f205c fix(web): thumbnail playback stops when hovering over icon then video (#16302)
fix thumbnail playback when hovering over icon then video
2025-02-24 21:35:46 -06:00
Alex 57829cee26 feat(web): slight fade in animation when open/close asset-viewer (#16262) 2025-02-24 16:38:07 -06:00
Yamagishi Kazutoshi 4be2351d21 fix(web): use anonymous function in setTimeout in ponyfill of requestIdelCallback (#16264) 2025-02-24 16:37:58 -06:00
Nicholas Flamy edbcf17e3a fix(docs): tsconfig issues in IDE (VSCode) - migrate tsconfig extends file to current docusaurus implementation (#16282)
fix tsx IDE (VSCode) issues in docs by migrating tsconfig extends from the Docusaurus tsconfig 2.X package to the 3.X package
2025-02-24 13:24:28 -06:00
Mert eef74ee0ba chore: bump justified layout library (#16298)
bump
2025-02-24 10:28:34 -06:00
Alex ec58e1065f fix(web): justify layout import (#16267)
* fix(web): justify layout import

* remove dead code
2025-02-23 02:38:08 +03:00
Mert 4376fd72b7 fix(web): dynamically import wasm module (#16261)
* dynamically import wasm module

* remove unused import
2025-02-22 12:16:06 -06:00
Jason Rasmussen e4b6efc1f5 fix: cross site scripting issue on /share pages (#16255) 2025-02-22 11:32:53 +00:00
waclaw66 caea3a0812 fix: vite > 6.0.8 allowedHosts (#16257)
fix(web): vite > 6.0.8 allowedHosts

Enables any host for development environment same as for vite <= 6.0.8
2025-02-21 23:29:58 -05:00
Jonathan Jogenfors 9c2c85cbe1 feat(web): remove library type column (#16254) 2025-02-21 18:00:16 -05:00
Jason Rasmussen d350022dec feat: persistent memories (#15953)
feat: memories

refactor

chore: use heart as favorite icon

fix: linting
2025-02-21 12:31:37 -06:00
Weblate (bot) 502f6e020d chore(web): update translations (#15559)
Co-authored-by: -J- <heyj0e@tuta.io>
Co-authored-by: 6Leoo6 <leo.takacs@yahoo.com>
Co-authored-by: Aldis Bārbelis <ceriemardon@gmail.com>
Co-authored-by: Alessandro Iaselli <alessandroias@gmail.com>
Co-authored-by: Andrea <andreadetomasi12@gmail.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Bora Atıcı <boratici.acc@gmail.com>
Co-authored-by: CRY WHY <a.pandagok1@gmail.com>
Co-authored-by: Casper Ong <casper10528@gmail.com>
Co-authored-by: Changhwan Kim <kimch061279@gmail.com>
Co-authored-by: Chris <6st6s7rgw@mozmail.com>
Co-authored-by: Christoph Auer <Christoph.Auer@pilsheim.de>
Co-authored-by: CodingDK <CodingDK@users.noreply.github.com>
Co-authored-by: Daniel <daniel@nikul.in>
Co-authored-by: Daniel A <aquino.daniel1994@ikmail.com>
Co-authored-by: Daniel Correa Lobato <daniel@lobato.org>
Co-authored-by: David Lam <dlam06@gmail.com>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Eitan Nargassi <eitan1112@gmail.com>
Co-authored-by: Fabian Tubbing <fabian@tubbing.nl>
Co-authored-by: Farid <farid.for@gmail.com>
Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Francesco Borio <borio.francesco@gmail.com>
Co-authored-by: HanYuan <lion70332@gmail.com>
Co-authored-by: Hurricane-32 <rodrigorimo@hotmail.com>
Co-authored-by: Indrek Haav <IndrekHaav@users.noreply.hosted.weblate.org>
Co-authored-by: Jan Schwebel <jan@schwebel.de>
Co-authored-by: Jirapan <jirapan_yankhan@hotmail.com>
Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
Co-authored-by: Jordy H <jordy@hoebergen.net>
Co-authored-by: Josep M. Ferrer <txemaq@gmail.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Karol Klimczak <karol.klimczak.1.kk@gmail.com>
Co-authored-by: Laurentiu <laurfb@gmail.com>
Co-authored-by: Leo Bottaro <github@leobottaro.com>
Co-authored-by: Leonardo Patti <leonardo.patti90@gmail.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Lukas Hamm <ideallygrey@tuta.io>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Mark Rieder <markrieder111@gmail.com>
Co-authored-by: Martin Popovski <martinkozle@yahoo.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Max Lengerer <lengerer.max@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki Mrvos <medolino2009@gmail.com>
Co-authored-by: Mohammed Al Otaibi <mopes.03.belle@icloud.com>
Co-authored-by: Nicolò <nicveronese@gmail.com>
Co-authored-by: Oleh Horbachov <gorbyo@gmail.com>
Co-authored-by: Pablo Portas López <pabloportas@protonmail.com>
Co-authored-by: Peder Vaagland <halsa.p.vaagland@gmail.com>
Co-authored-by: Petri Hämäläinen <petri.hamalainen@mailbox.org>
Co-authored-by: Rafa <rafa0292@gmail.com>
Co-authored-by: Ram Sujith Reddibathini (Ram) <sujithram.it@gmail.com>
Co-authored-by: Riccardo <lark-unit-rush@duck.com>
Co-authored-by: Rodrigo Bourbon Navarro <rodrigobourbon44@gmail.com>
Co-authored-by: Roi Gabay <roigby@gmail.com>
Co-authored-by: Rookie Nguyễn <nguyenquocthang2004@gmail.com>
Co-authored-by: Runskrift <anders@rimfrost.nu>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: Theofilos Nikolaou <th.nikolaou@gmail.com>
Co-authored-by: Torin Wu <xuan329269@gmail.com>
Co-authored-by: Vegard Fladby <vegard@fladby.org>
Co-authored-by: Vladislav Tkalin <mrtold11@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: YapWC <yapchengcheng3568@gmail.com>
Co-authored-by: Zulhilmi Ramli <ramli.zulhilmi@gmail.com>
Co-authored-by: anton garcias <isaga.percompartir@gmail.com>
Co-authored-by: chamdim <chamdim@protonmail.com>
Co-authored-by: chapvic <victor@chapaev.org>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: iancbogue <iancbogue@gmail.com>
Co-authored-by: intothevolt <francesco.ferriero97@gmail.com>
Co-authored-by: kiwinho <kiwicaja@gmail.com>
Co-authored-by: krzemyk <krzemyk.official@proton.me>
Co-authored-by: pierrebengtsson <pierre.bengtsson@gmail.com>
Co-authored-by: shiuh67 <shiuh.cheng@gmail.com>
Co-authored-by: szelek <janek.szelewicz@gmail.com>
Co-authored-by: thehijacker <thehijacker@gmail.com>
Co-authored-by: timmy61109 <qazzxcasdqwewsxedc@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: wickdj <wickdj@gmail.com>
Co-authored-by: wojtasiq <wojtek.wroclaw@hotmail.com>
Co-authored-by: xmh10000 <xmh10000@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
Co-authored-by: Мĕтри Сантăр ывалĕ Упа-Миччи <mefisteron@gmail.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-02-21 17:30:19 +00:00
bo0tzz ca9e02379d feat: remove preview label on pr close (#16249) 2025-02-21 17:54:11 +01:00
bo0tzz 36ec407c66 fix: use correct head sha on PR commit tag (#16248) 2025-02-21 17:02:24 +01:00
Alex 007eaaceb9 feat(web): manual face tagging and deletion (#16062) 2025-02-21 09:58:25 -06:00
shenlong 94c0e8253a test(mobile): store (#16243)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-02-21 09:10:42 -06:00
Alex 5acf6868b7 refactor(mobile): render list (#16239)
* refactor(mobile): trash provider

* refactor(mobile): trash provider

* pr feedback

* archive timeline

* favorite

* album

* trash timeline

* all videos timeline

* refactor

* refactor: home timeline and partner timeline

* update analysis option
2025-02-21 09:01:46 -06:00
Mert 616905211d fix(server): assets in multiple albums duplicated in map view (#16245) 2025-02-21 15:32:08 +03:00
Mert 3925445de8 feat(web): use wasm for justified layout calculation (#15524)
* working

* use wrapper class

* update import

* simplify

* it works without changing `optimizeDeps`

* inline layout options

* update gallery view

* use es2022

* fix import

* fix vitest

* empty geometry

* bump version

* Update web/src/lib/stores/assets.store.ts

Co-authored-by: Jason Rasmussen <jason@rasm.me>

* fix: typo

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-02-21 09:20:25 +00:00
Mert 52f21fb331 fix(web): viewport reactivity, off-screen thumbhashes being rendered (#15435)
* viewport optimizations

* fade in

* async bitmap

* fast path for smaller date groups

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-20 22:38:12 -06:00
Zack Pollard ac36effb45 feat: sync implementation for the user entity (#16234)
* ci: print out typeorm generation changes

* feat: sync implementation for the user entity

wip

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-02-20 23:37:57 -05:00
bo0tzz 02cd8da871 docs: clarify custom locations guide (#16122) 2025-02-20 22:31:29 -06:00
Alex 17a2043e76 refactor(mobile): trash provider (#16219)
* refactor(mobile): trash provider

* refactor(mobile): trash provider

* pr feedback
2025-02-20 22:14:41 -06:00
Jason Antwi-Appah 34b88bb47a feat(web): support searching by EXIF rating (#16208)
* Add rating to search DTO

* Add search by EXIF rating in search query builder

* Generate OpenAPI spec

* Add rating filter on web

* Add rating filter to search docs

* Format / lint

* Hide rating filter if ratings are disabled

* chore: component order in form

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-02-20 16:17:06 +00:00
Jonathan Jogenfors f6ba071569 feat(server): add path to metadata logging (#16212)
feat(server): Prefer original path instead of id when logging
2025-02-20 09:46:18 -06:00
Jonathan Jogenfors 6b7a7b0cbc feat(web): library import path onboarding (#16229) 2025-02-20 09:45:34 -06:00
Jonathan Jogenfors b0102f8025 fix(server): set modifydate (#16225) 2025-02-20 09:28:30 -06:00
Lukas 9c95adc7fb feat(web): show memories in portrait on small screens (#16213) 2025-02-19 23:15:45 +00:00
renovate[bot] 376282e538 chore(deps): update dependency @types/node to ^22.13.4 (#16206)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-19 14:54:12 -06:00
shenlong 76d95cd348 refactor(mobile): move store settings and store into domain folder (#16201)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-02-19 19:27:32 +00:00
Jonathan Jogenfors 31dc83f3f2 fix(server): don't warn about missing timezone (#16211)
fix(server): don't warn about timezone
2025-02-19 13:21:13 -06:00
shenlong aeb3e0a84f refactor(mobile): split store into repo and service (#16199)
* refactor(mobile): migrate store

* refactor(mobile): expand abbreviations

* chore(mobile): fix lint

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-19 13:05:24 -06:00
Krassimir Valev 8634c59850 feat(server): search by partial asset path (#16173)
Similarly to how one can search by partial filename, change the
path search to work with partial matches instead of looking for a
full match.

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-19 08:32:52 -06:00
Lukas b13a98646f fix(web): improve memories layout on small screens (#16162)
* fix(web): improve memories layout on small screens

* decrease viewer height
2025-02-18 17:40:52 -06:00
renovate[bot] 7bf142dc43 chore(deps): update prom/prometheus docker digest to 5888c18 (#16171)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 16:02:56 -05:00
renovate[bot] d8cda6ee40 chore(deps): update base-image to v20250218 (major) (#16204)
chore(deps): update base-image to v20250218

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 16:02:33 -05:00
renovate[bot] a31bc94460 fix(deps): update typescript-projects (#16203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 21:35:50 +01:00
renovate[bot] 516709ffe1 chore(deps): update dependency @types/node to ^22.13.2 (#16200)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 15:10:44 -05:00
renovate[bot] 425cf62482 fix(deps): update typescript-projects (#16178)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-02-18 20:40:09 +01:00
Jason Anderson 58242b3b4a chore(docs): Synology set-up guide (#16179)
* Addition of Synology set-up guide

* fix: format

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-18 13:39:42 -06:00
Alex 9d4aee36e2 refactor(mobile): asset provider (#16159)
* refactor(mobile): asset provider

* wip

* wip: delete local assets

* wip: delete remote assets

* wip: deletion logic

* refactor

* pr feedback
2025-02-18 13:10:55 -06:00
shenlong 70d08a2b2a chore(mobile): lint (#16182)
* lint - convert path to lowercase for finding index

* update dcm lint rules

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-02-18 09:34:19 -06:00
Zack Pollard f1b98d5f45 ci: docker cleanup, cleanup (#16194) 2025-02-18 14:56:58 +00:00
bo0tzz 749eff03d5 fix: pgvectors docs link (#16187)
Fixes #16184
2025-02-18 08:38:07 -05:00
bo0tzz 5f257b9a84 fix: don't write cache on fork PRs (#16189) 2025-02-18 12:47:20 +01:00
Jonathan Jogenfors 0cae20033c fix(server): more e2e library flakiness cleanup (#16176) 2025-02-17 19:04:38 -05:00
Jonathan Jogenfors 115ee0d6cc fix(server): remove unused readme (#16175)
fix(server): remove readme
2025-02-17 19:03:43 -05:00
Jonathan Jogenfors bfdd6eac01 fix(server): flaky library e2e tests (#16174) 2025-02-17 18:26:44 -05:00
bo0tzz 9eab770e79 fix: don't push on forks (#16165) 2025-02-17 20:13:56 +00:00
João Paulo Ros efd8d8b884 fix(mobile): Server endpoint on the login screen. (#16149)
Fixing the server endpoint on the login screen. It added the "/api" suffix instead of using the default method getServerUrl, which takes care of sanitizing the URL.

Co-authored-by: Joao Paulo Ros <ros@voxit.ai>
2025-02-17 19:12:48 +00:00
Alessandro Craciun 25e1c8cc7f chore(web): update italian translations (#15695) 2025-02-17 13:09:55 -06:00
Jason Rasmussen 7c26663013 chore: removed unused endpoint (#16167) 2025-02-17 13:07:50 -06:00
bo0tzz 2c88ce8559 chore: run full jobs on workflow file change (#16166) 2025-02-17 12:09:38 -06:00
Nick Overacker 50b072803d fix: limit width of logo in emails to 100% (#16164)
Limit width of logo in emails to 100%

The current live version breaks Yahoo Mail (at least in Firefox). It appears far too large and makes the email unreadable by pushing the text outside of the reading pane.
2025-02-17 17:46:14 +00:00
Mangat Singh Toor | ਮੰਗਤ ਸਿੰਘ ਤੂਰ 1689cecaf7 fix: include live images in person view count (#16116)
* fix: include live images in person view count

Fixed an issue where the total image count in the person view excluded live images.
The query now correctly accounts for all relevant assets by removing the condition
that filtered out assets with a livePhotoVideoId.

Issue:
- Image count under a person’s name was inaccurate, showing only static images.

Fix:
- Removed `.on('assets.livePhotoVideoId', 'is', null)` from the LEFT JOIN condition.

Tested on:
- Web

Ran PR checklist

* chore: run make sql.

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-17 15:49:30 +00:00
Pablo P Varela 5cd1018db3 fix(mobile): failed to load gl-ES locale (#16123) 2025-02-17 08:48:55 -06:00
renovate[bot] 31e6270a28 chore(deps): update docker.io/redis:6.2-alpine docker digest to 148bb54 (#16113)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-17 14:23:28 +00:00
renovate[bot] b3fbd0809b chore(deps): update redis:6.2-alpine docker digest to 148bb54 (#16140)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-17 14:23:03 +00:00
Zack Pollard 129a4a82e0 ci: docker build cache (#16156) 2025-02-17 13:55:22 +00:00
Zack Pollard 924d11a913 ci: copy image layers from ghcr to dockerhub on release (#16155) 2025-02-17 13:41:45 +00:00
Zack Pollard 425c87bce4 ci: machine learning separate native docker image builds (#16102) 2025-02-17 11:56:28 +00:00
bo0tzz 25fcda6eeb chore: add warning to all compose files (#16146) 2025-02-16 21:28:59 -06:00
Jason Rasmussen f386b4d377 feat(web): use thumbhash as a cache key (#16106)
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-16 03:34:13 +00:00
renovate[bot] c524fcf084 chore(deps): update node.js to v22.14.0 (#16132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-15 21:29:33 -06:00
renovate[bot] 194c567a45 chore(deps): update redis:6.2-alpine docker digest to 785233c (#16114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-15 12:10:44 +00:00
Zack Pollard 411f96ef49 fix: place suggestions not clickable in asset set location modal (#16104)
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-15 09:44:11 +00:00
Alex 4f912de018 refactor(mobile): album provider (#16099) 2025-02-14 19:27:39 -06:00
Alex 47203d2760 refactor(mobile): asset stack provider (#16100)
* refactor(mobile): asset stack provider

* remove file from ignore list
2025-02-14 13:23:14 -06:00
Zack Pollard 8ab87a8803 ci: retag commit hash unset outside of PRs (#16103) 2025-02-14 19:18:49 +01:00
Zack Pollard 5b4f894211 ci: docker images sha commit tag (#16098) 2025-02-14 16:08:41 +00:00
Mangat Singh Toor | ਮੰਗਤ ਸਿੰਘ ਤੂਰ b1f05fc18b fix(web): properly project profile picture (#16095)
* fix(profile-image-cropper): ensure correct image area is saved after transparency check

Fixed an issue where users could not set a profile picture due to incorrect transparency detection.
After addressing transparency detection by passing explicit dimensions, another issue arose where the
generated blob did not represent the correct cropped image area. To fix this, a new cropped blob was generated using the canvas that was used to check for transparent pixels.

- Pass image width and height explicitly to `hasTransparentPixels` for accurate processing.
- Return both transparency status and the correctly cropped image blob.
- Ensure the final uploaded image is taken from `croppedImageBlob` to reflect user adjustments.

* chore: run pr web checklist. No issues in the changed file.

* fix(profile-image-cropper): ensure correct image area is saved after transparency check

Fixed an issue where users could not set a profile picture due to incorrect transparency detection.
To fix this, a new cropped blob was generated using the height and width of the imgElement.

Note: this is a simpler fix than the one in the previous commit.

* lint

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-02-14 15:49:22 +00:00
Zack Pollard dbbefde98d feat: native arm and amd64 server builds (#15408) 2025-02-14 15:55:18 +01:00
Jonathan Jogenfors 5407a28533 feat(server): Nullable asset dates (#15669)
* nullable dates

* wip

* don't search for null dates

* Add placeholder type

* cleanup
2025-02-13 15:30:12 -06:00
bo0tzz f5edc87e4d feat: comment URL on previewed PRs (#16085) 2025-02-13 21:10:00 +00:00
HelloMihai bf16b61d43 fix: broken html id (#16084)
ids cannot have spaces

relative should not be in the ID of the element
2025-02-13 14:46:12 -05:00
Joren Guillaume 8c882b54cd docs: put Windows restore command on one line (#16074)
Lots of 'unexpected newline' comments when restoring from other users, this should fix that.
2025-02-13 05:44:33 -05:00
Jason Rasmussen 2d7c333c8c refactor(server): narrow auth types (#16066) 2025-02-12 15:23:08 -05:00
Yaros 7c821dd205 feat(mobile): Made Map Bottom Sheet extendable higher (#16056)
Made Map Bottom Sheet extendable higher
2025-02-12 14:56:50 +00:00
renovate[bot] 703361da1a chore(deps): update dependency svelte to v5.19.9 (#16043)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-11 17:24:39 -06:00
Jason Rasmussen fa5aeaf539 refactor: last repository (#16042) 2025-02-11 22:15:56 +00:00
Jason Rasmussen 5f3a42a132 refactor: repositories (#16038) 2025-02-11 15:12:31 -05:00
Jason Rasmussen 9d85272c2b refactor: repositories (#16036) 2025-02-11 14:08:13 -05:00
renovate[bot] d2575d8f00 fix(deps): update typescript-projects (#16023)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-02-11 18:50:18 +00:00
renovate[bot] f0a4c945bd chore(deps): update github-actions (#16032)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-11 17:24:47 +00:00
renovate[bot] a3766b879e fix(deps): update machine-learning (#16012)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-11 11:23:54 -06:00
Alex 1a190c33a0 chore(mobile): post release task (#16004) 2025-02-11 11:23:02 -06:00
renovate[bot] 17a63e37b2 chore(deps): update base-image to v20250211 (major) (#16025)
chore(deps): update base-image to v20250211

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-11 11:21:25 -06:00
renovate[bot] bf1f8da884 chore(deps): update docker/build-push-action action to v6.13.0 (#16022)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-11 14:16:10 +01:00
renovate[bot] 2271984dbd chore(deps): update dependency @types/node to ^22.13.1 (#16013)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-11 00:19:02 +00:00
Snowknight26 b40963ec52 fix(web): Update shared link Exif capitalization to match existing capitalization (#16010)
Update shared link Exif capitalization to match existing capitalization
2025-02-10 19:00:37 -05:00
Jason Rasmussen 735f8d661e refactor: test mocks (#16008) 2025-02-11 00:47:42 +01:00
github-actions 8794c84e9d chore: version v1.126.1 2025-02-10 17:54:02 +00:00
Alex cef19eed97 chore(mobile): patch openapi preference (#16000) 2025-02-10 17:39:43 +00:00
Alex 90c607c1a6 chore(mobile): post release task (#15998) 2025-02-10 11:12:36 -06:00
Daniel Dietzler 52b650093d fix: merch link (#15999) 2025-02-10 16:56:40 +00:00
Parsa Poorshikhian fe4c49c8e3 chore: update of the persian translation (#15972)
* chore: update of the persian translation

* chore: update of the persian translation

* chore: update of the persian translation

* chore: update of the persian translation
2025-02-10 16:47:53 +00:00
Nicholas Flamy 4cad23aaa3 docs: add-hash #15860 follow-up (#15988)
add-hash
2025-02-10 10:46:47 -06:00
github-actions feba590de7 chore: version v1.126.0 2025-02-10 16:10:06 +00:00
renovate[bot] 64f0333306 chore(deps): update grafana/grafana docker tag to v11.5.1 (#15963)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-09 07:00:37 -05:00
Jason Rasmussen 758bcd1e97 fix(server): validate oauth profile has a sub (#15967) 2025-02-08 17:01:28 -05:00
Alex fb21950ad8 chore(web): shared links style tweaks (#15960) 2025-02-07 20:53:12 -05:00
Jason Rasmussen 758449e9f0 refactor: session repository (#15957) 2025-02-07 23:16:40 +00:00
Jason Rasmussen d7d4d22fe0 refactor: process repository (#15956) 2025-02-07 18:04:04 -05:00
Jason Rasmussen 03948a69e2 refactor: system metadata repository (#15954) 2025-02-07 17:26:49 -05:00
Jason Rasmussen 61b8eb85b5 feat: view album shared links (#15943) 2025-02-07 16:38:20 -05:00
Jason Rasmussen c5360e78c5 feat(web): shared link filters (#15948) 2025-02-07 13:05:15 -05:00
Jason Rasmussen 23014c263b feat(api): set person color (#15937) 2025-02-07 10:06:58 -05:00
Mert 2e5007adef docs: soften wording for openvino igpu (#15941) 2025-02-07 06:44:22 -05:00
Nicholas Flamy c4531fc4d3 fix(docs): show version selection dropdown on mobile (#15894)
change-className-and-add-css-to-show-versions-on-mobile
2025-02-06 16:00:52 -05:00
renovate[bot] 252d3f5f2c chore(deps): update grafana/grafana docker tag to v11.5.0 (#15930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-06 15:59:47 -05:00
renovate[bot] ef6c2bf547 chore(deps): update base-image to v20250204 (major) (#15931)
chore(deps): update base-image to v20250204

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-06 15:59:29 -05:00
Krassimir Valev 6aad9fae8e feat(web): revamp places (#12219)
* revamp places

* add english translations

* migrate places page and components to svelte 5

* fix lint

* chore: cleanup

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-02-06 20:54:01 +00:00
Daniel Dietzler 45f7401513 chore: nestjs 11 (#15542) 2025-02-06 13:56:26 -05:00
renovate[bot] 3c7edba388 chore(deps): update terraform cloudflare to v4.52.0 (#15526)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-06 13:52:27 -05:00
renovate[bot] 76a70703a5 chore(deps): update base-image to v20250128 (major) (#15796)
chore(deps): update base-image to v20250128

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-06 13:51:52 -05:00
Ridvan f78066d4b9 Update setup.md to include FVM dependency (#15927) 2025-02-06 18:50:55 +00:00
Jason Rasmussen 48d421e28c fix(server): always get UTC dates from postgres (#15920) 2025-02-05 18:47:27 +00:00
defooster 1492b55c07 fix(docs): typo in unraid.md (#15913)
Update unraid.md

fixed wrong word
2025-02-05 09:35:55 -06:00
bo0tzz 1d6a4e9318 fix: call hexOrBufferToBase64 for stripMetadata thumbhash (#15917)
Fixes #15916 (I think)
2025-02-05 09:20:46 -06:00
Alex fe42e7410b chore(server): follow up on #15899 (#15907) 2025-02-04 16:57:11 -06:00
Jason Rasmussen 58bf58b393 refactor: get map markers database query (#15899) 2025-02-04 09:07:41 -06:00
Nicholas Flamy 99de52479e fix: pr template not being used and make some changes (#15893)
fix-pr-template-and-make-some-changes-with-suggestions
2025-02-04 09:06:54 -06:00
André Ventura 97574d7296 fix(web): prevent accidental modal closures on mouseup outside (#15900) 2025-02-04 13:43:19 +00:00
Nicholas Flamy 5015210f37 docs: add-current-path-to-version-switcher (#15860)
add-current-path-to-version-switcher
2025-02-04 04:09:07 -05:00
Lukas 0bb1219b5f fix(server): for individual shares not showing thumbnails (#15895)
* Fix for individual shares not showing thumbnails

* synced sql

* chore: add e2e test

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2025-02-04 09:07:50 +00:00
Jonathan Jogenfors b730aa60ed fix(server): queue missing metadata (#15864)
fix: queue missing metadata
2025-02-04 04:00:39 -05:00
Arno 7ec3610753 feat: Mark people as favorite (#14866)
* feat: added ability to mark people as favorite, which get sorted to the front of the people list

* feat(server): added unit test for favorite people

* feat(server): refactored for better readability

* fixed person service unit tests

* fixed open-api and sql checks

* fixed bad codegen and removed unnecessary type assertion again

* chore: clean up

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2025-02-04 08:52:17 +00:00
Tom Graham 69e88ef985 fix(mobile): #15182 Video memories no longer play (#15210)
* Update current asset to play video.

* Updated location of currentAssetProvider update per feedback.

* Added a playbackDelayFactor to the video viewer to resolve an issue in memories.

Also adjusted the scale of the memory preview image to match the ratio of the video. This still appears to jump because the video preview doesn't seem to be the first frame for some reason :\

* add video indicator

---------

Co-authored-by: Tom graham <tomg@questps.com.au>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-03 22:43:23 +00:00
jtkmckenna 9358b4dc7e fix: bash install.sh script for mac os (#15874)
fix: bash script for mac os

Fix the displayed IP address in bash script if hostname fails to return a string

Co-authored-by: Joseph McKenna <dev@jtkmckenna.com>
2025-02-03 16:41:42 -06:00
Alex 06f077bac2 fix(server): memory lane assets order (#15882)
* fix(server): memory lane assets order

* fix: sql

* pr feedback

* sql
2025-02-03 16:29:41 -06:00
Meesam 47f6181d42 fix(mobile): improved the visibility of backup cloud icon on lighter images (#15886)
* fix(mobile): improved the visibility of backup cloud icon on lighter images

* refactor(mobile): add 'const' keyword to Offset constructor for improved performance
2025-02-03 20:30:39 +00:00
André Ventura aac029d92b feat(web): merge suggestion modal: focus on Yes button by default. (#15827)
* feat(web): merge suggestion modal: focus on Yes button by default.

* refactor(web): merge suggestion modal: use Button from @immich/ui.

---------

Co-authored-by: André Ventura <afv@users.noreply.github.com>
2025-02-03 14:01:05 -06:00
Damiano Ferrari ef245ea2d2 feat(mobile): Use NavigationRail when the screen is in landscape mode (#15885) 2025-02-03 13:49:55 -06:00
Stark e8d05e78ad feat(web): Updated Onboarding page (#15880)
Updated Onboarding page

the "previous" button on the Storage Template page now points to privacy instead of theme
2025-02-03 17:36:25 +00:00
Matthew Momjian 52c9fbea5f fix(docs): query DB by ID (#15863)
* db query for id

* format

* backticks

* Update database-queries.md
2025-02-02 22:55:47 -06:00
bo0tzz 882163f545 chore: build metadata for ML container (#15831)
* chore: build metadata for ML container

* fix: build_image_url
2025-02-02 23:45:58 +01:00
Damiano Ferrari 96a6cc20b7 refactor(mobile): Use switch expression when possible (#15852)
refactor: Use `switch` expression when possible

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-02-02 15:46:46 -06:00
Alex 4efacfbb91 feat: search by description (#15818)
* feat: search by description

* wip: mobile

* wip: mobile ui

* wip: mobile search logic

* feat: using f_unaccent

* icon to fit with text search
2025-02-02 15:18:13 -06:00
Matthew Momjian a808a840c8 fix(mobile): title of custom proxy headers (#15859)
fix title
2025-02-02 20:43:14 +00:00
Nicholas Flamy 3f18acdb1a docs: TrueNAS: add danger message to external libraries (#15857)
Add danger message to external libraries in truenas.md (Format fix included)
2025-02-02 12:07:39 -06:00
Zack Pollard 2b41b5efe1 feat: merch links (#15843) 2025-02-02 00:26:23 +01:00
David Wolff 9ac95d6845 feat: add searching by tags (#15395)
* feat: add searching by tags

* fix: fix merge

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-01-31 21:37:22 +00:00
Mangat Singh Toor | ਮੰਗਤ ਸਿੰਘ ਤੂਰ 221e197633 fix(mobile): retain edited title when album updates (#15806)
* fix(album-viewer): retain edited title when album updates

ensure `AlbumViewerEditableTitle` keeps user input while editing,
even when the album updates from another provider. fall back to
`albumName` only when not in edit mode.

* linting

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-01-31 09:24:53 -06:00
David Wolff 1b141d5ca9 refactor(server): filter assets by people using a subquery instead of a cte (#15768) 2025-01-31 09:06:45 -06:00
Alex 098bab7c9b fix(mobile): search page issues (#15804)
* fix: don't repeat search

* fix: show snackbar for no result

* fix: do not search on empty filter

* chore: syling
2025-01-31 03:12:57 +00:00
Felix Eckhofer 4fccc09fc1 chore: fix typo in libraries.md (#15800)
Fix typo in libraries.md
2025-01-30 20:34:12 -06:00
Jason Rasmussen c016b65ef2 fix(web): shared link date range (#15802) 2025-01-30 18:36:45 -05:00
preeperkiller 844eed8707 fix(web): HelpAndFeedback button the same size as Theme button in navbar (#15791)
fix(server): HelpAndFeedback button the same size as Theme button in navbar
2025-01-30 12:43:35 -05:00
Justin Forseth 6e31ac4c75 feat(mobile): Add filter to people_picker.dart (#15771)
* Add filter to people_picker.dart

* feat: styling

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-01-29 21:02:54 +00:00
Jirapan. b287c0cbe8 chore: update of the Thai translation (#15758) 2025-01-29 20:29:50 +00:00
Jason Rasmussen 1fcc75fb44 docs: update server arch (#15775) 2025-01-29 13:42:38 -06:00
Jonathan Jogenfors ca79e25a6e feat(server): synology exclusion patterns (#15773)
feat: add synology exclusion patterns
2025-01-29 13:42:21 -06:00
github-actions 4fd8c1b3c1 chore: version v1.125.7 2025-01-29 17:41:38 +00:00
Antonio Sarro f3ba994186 fix(web): update recent album after edit (#15762)
* fix(web): update recent album after edit

* chore: clean up

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2025-01-29 17:27:30 +00:00
Ben Cochran b4a4abbf51 fix(docs): move a few API doc comments to descriptions (#15381)
Previously, the comments were being used as the summaries, and thus were
displayed as the “title” of these endpoints
2025-01-29 11:58:10 -05:00
Jason Rasmussen a0aea021a1 fix(server): restore user (#15763) 2025-01-29 16:49:08 +00:00
Joren Guillaume 9033a99587 fix(server): Update vaapi-wsl to include dxg (#15759) 2025-01-29 16:39:02 +01:00
ayykamp cc0cbd705e feat: add support for JPEG 2000 (#15710)
* chore(server): add support for .jp2

* docs: add support for .jp2

* chore: fix tests

* fix formatting

* unify sorting
2025-01-28 23:27:28 +00:00
1587 changed files with 100391 additions and 76404 deletions
+2 -2
View File
@@ -1,10 +1,10 @@
ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22@sha256:9791f4aa527774bc370c6bd2f6705ce5a686f1e6f204badd8dfaacce28c631ae ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22@sha256:a20b8a3538313487ac9266875bbf733e544c1aa2091df2bb99ab592a6d4f7399
FROM ${BASEIMAGE} FROM ${BASEIMAGE}
# Flutter SDK # Flutter SDK
# https://flutter.dev/docs/development/tools/sdk/releases?tab=linux # https://flutter.dev/docs/development/tools/sdk/releases?tab=linux
ENV FLUTTER_CHANNEL="stable" ENV FLUTTER_CHANNEL="stable"
ENV FLUTTER_VERSION="3.24.5" ENV FLUTTER_VERSION="3.29.1"
ENV FLUTTER_HOME=/flutter ENV FLUTTER_HOME=/flutter
ENV PATH=${PATH}:${FLUTTER_HOME}/bin ENV PATH=${PATH}:${FLUTTER_HOME}/bin
+3
View File
@@ -6,6 +6,9 @@ mobile/openapi/**/*.dart linguist-generated=true
mobile/lib/**/*.g.dart -diff -merge mobile/lib/**/*.g.dart -diff -merge
mobile/lib/**/*.g.dart linguist-generated=true mobile/lib/**/*.g.dart linguist-generated=true
mobile/lib/**/*.drift.dart -diff -merge
mobile/lib/**/*.drift.dart linguist-generated=true
open-api/typescript-sdk/fetch-client.ts -diff -merge open-api/typescript-sdk/fetch-client.ts -diff -merge
open-api/typescript-sdk/fetch-client.ts linguist-generated=true open-api/typescript-sdk/fetch-client.ts linguist-generated=true
+1
View File
@@ -0,0 +1 @@
22.14.0
@@ -1,5 +1,5 @@
title: "[Feature] feature-name-goes-here" title: '[Feature] feature-name-goes-here'
labels: ["feature"] labels: ['feature']
body: body:
- type: markdown - type: markdown
@@ -11,9 +11,9 @@ body:
- type: checkboxes - type: checkboxes
attributes: attributes:
label: I have searched the existing feature requests to make sure this is not a duplicate request. label: I have searched the existing feature requests, both open and closed, to make sure this is not a duplicate request.
options: options:
- label: "Yes" - label: 'Yes'
required: true required: true
- type: textarea - type: textarea
+1 -1
View File
@@ -1 +1 @@
custom: ['https://buy.immich.app'] custom: ['https://buy.immich.app', 'https://immich.store']
+11 -3
View File
@@ -1,6 +1,13 @@
name: Report an issue with Immich name: Report an issue with Immich
description: Report an issue with Immich description: Report an issue with Immich
body: body:
- type: checkboxes
attributes:
label: I have searched the existing issues, both open and closed, to make sure this is not a duplicate report.
options:
- label: 'Yes'
required: true
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
@@ -77,7 +84,7 @@ body:
id: repro id: repro
attributes: attributes:
label: Reproduction steps label: Reproduction steps
description: "How do you trigger this bug? Please walk us through it step by step." description: 'How do you trigger this bug? Please walk us through it step by step.'
value: | value: |
1. 1.
2. 2.
@@ -90,12 +97,13 @@ body:
id: logs id: logs
attributes: attributes:
label: Relevant log output label: Relevant log output
description: Please copy and paste any relevant logs below. (code formatting is description:
Please copy and paste any relevant logs below. (code formatting is
enabled, no need for backticks) enabled, no need for backticks)
render: shell render: shell
validations: validations:
required: false required: false
- type: textarea - type: textarea
attributes: attributes:
label: Additional information label: Additional information
-1
View File
@@ -1,2 +1 @@
blank_issues_enabled: false
blank_pull_request_template_enabled: false blank_pull_request_template_enabled: false
@@ -1,22 +0,0 @@
## Description
<!--- Describe your changes in detail -->
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
Fixes # (issue)
## How Has This Been Tested?
<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration -->
- [ ] Test A
- [ ] Test B
## Screenshots (if appropriate):
## Checklist:
- [ ] I have performed a self-review of my own code
- [ ] I have made corresponding changes to the documentation if applicable
+28
View File
@@ -0,0 +1,28 @@
{
"name": ".github",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"devDependencies": {
"prettier": "^3.5.3"
}
},
"node_modules/prettier": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
}
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"scripts": {
"format": "prettier --check .",
"format:fix": "prettier --write ."
},
"devDependencies": {
"prettier": "^3.5.3"
}
}
+36
View File
@@ -0,0 +1,36 @@
## Description
<!--- Describe your changes in detail -->
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
Fixes # (issue)
## How Has This Been Tested?
<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration -->
- [ ] Test A
- [ ] Test B
<details><summary><h2>Screenshots (if appropriate)</h2></summary>
<!-- Images go below this line. -->
</details>
<!-- API endpoint changes (if relevant)
## API Changes
The `/api/something` endpoint is now `/api/something-else`
-->
## Checklist:
- [ ] I have performed a self-review of my own code
- [ ] I have made corresponding changes to the documentation if applicable
- [ ] I have no unrelated changes in the PR.
- [ ] I have confirmed that any new dependencies are strictly necessary.
- [ ] I have written tests for new code (if applicable)
- [ ] I have followed naming conventions/patterns in the surrounding code
- [ ] All code in `src/services/` uses repositories implementations for database calls, filesystem operations, etc.
- [ ] All code in `src/repositories/` is pretty basic/simple and does not have any immich specific logic (that belongs in `src/services/`)
+33 -33
View File
@@ -1,33 +1,33 @@
changelog: changelog:
categories: categories:
- title: 🚨 Breaking Changes - title: 🚨 Breaking Changes
labels: labels:
- changelog:breaking-change - changelog:breaking-change
- title: 🫥 Deprecated Changes - title: 🫥 Deprecated Changes
labels: labels:
- changelog:deprecated - changelog:deprecated
- title: 🔒 Security - title: 🔒 Security
labels: labels:
- changelog:security - changelog:security
- title: 🚀 Features - title: 🚀 Features
labels: labels:
- changelog:feature - changelog:feature
- title: 🌟 Enhancements - title: 🌟 Enhancements
labels: labels:
- changelog:enhancement - changelog:enhancement
- title: 🐛 Bug fixes - title: 🐛 Bug fixes
labels: labels:
- changelog:bugfix - changelog:bugfix
- title: 📚 Documentation - title: 📚 Documentation
labels: labels:
- changelog:documentation - changelog:documentation
- title: 🌐 Translations - title: 🌐 Translations
labels: labels:
- changelog:translation - changelog:translation
+13 -7
View File
@@ -22,16 +22,18 @@ jobs:
should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }} should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- id: found_paths - id: found_paths
uses: dorny/paths-filter@v3 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
with: with:
filters: | filters: |
mobile: mobile:
- 'mobile/**' - 'mobile/**'
workflow:
- '.github/workflows/build-mobile.yml'
- name: Check if we should force jobs to run - name: Check if we should force jobs to run
id: should_force id: should_force
run: echo "should_force=${{ github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' }}" >> "$GITHUB_OUTPUT" run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' }}" >> "$GITHUB_OUTPUT"
build-sign-android: build-sign-android:
name: Build and sign Android name: Build and sign Android
@@ -49,18 +51,18 @@ jobs:
ref="${input_ref:-$github_ref}" ref="${input_ref:-$github_ref}"
echo "ref=$ref" >> $GITHUB_OUTPUT echo "ref=$ref" >> $GITHUB_OUTPUT
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
ref: ${{ steps.get-ref.outputs.ref }} ref: ${{ steps.get-ref.outputs.ref }}
- uses: actions/setup-java@v4 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
with: with:
distribution: 'zulu' distribution: 'zulu'
java-version: '17' java-version: '17'
cache: 'gradle' cache: 'gradle'
- name: Setup Flutter SDK - name: Setup Flutter SDK
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2
with: with:
channel: 'stable' channel: 'stable'
flutter-version-file: ./mobile/pubspec.yaml flutter-version-file: ./mobile/pubspec.yaml
@@ -76,6 +78,10 @@ jobs:
working-directory: ./mobile working-directory: ./mobile
run: flutter pub get run: flutter pub get
- name: Generate translation file
run: make translation
working-directory: ./mobile
- name: Build Android App Bundle - name: Build Android App Bundle
working-directory: ./mobile working-directory: ./mobile
env: env:
@@ -87,7 +93,7 @@ jobs:
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64 flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
- name: Publish Android Artifact - name: Publish Android Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with: with:
name: release-apk-signed name: release-apk-signed
path: mobile/build/app/outputs/flutter-apk/*.apk path: mobile/build/app/outputs/flutter-apk/*.apk
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Cleanup - name: Cleanup
run: | run: |
+8 -9
View File
@@ -6,7 +6,6 @@ on:
- 'cli/**' - 'cli/**'
- '.github/workflows/cli.yml' - '.github/workflows/cli.yml'
pull_request: pull_request:
branches: [main]
paths: paths:
- 'cli/**' - 'cli/**'
- '.github/workflows/cli.yml' - '.github/workflows/cli.yml'
@@ -29,9 +28,9 @@ jobs:
working-directory: ./cli working-directory: ./cli
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
# Setup .npmrc file to publish to npm # Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './cli/.nvmrc' node-version-file: './cli/.nvmrc'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
@@ -53,16 +52,16 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3.3.0 uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.8.0 uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
if: ${{ !github.event.pull_request.head.repo.fork }} if: ${{ !github.event.pull_request.head.repo.fork }}
with: with:
registry: ghcr.io registry: ghcr.io
@@ -77,7 +76,7 @@ jobs:
- name: Generate docker image tags - name: Generate docker image tags
id: metadata id: metadata
uses: docker/metadata-action@v5 uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
with: with:
flavor: | flavor: |
latest=false latest=false
@@ -88,7 +87,7 @@ jobs:
type=raw,value=latest,enable=${{ github.event_name == 'release' }} type=raw,value=latest,enable=${{ github.event_name == 'release' }}
- name: Build and push image - name: Build and push image
uses: docker/build-push-action@v6.12.0 uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
with: with:
file: cli/Dockerfile file: cli/Dockerfile
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
+31 -32
View File
@@ -9,14 +9,14 @@
# the `language` matrix defined below to confirm you have the correct set of # the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages. # supported CodeQL languages.
# #
name: "CodeQL" name: 'CodeQL'
on: on:
push: push:
branches: [ "main" ] branches: ['main']
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "main" ] branches: ['main']
schedule: schedule:
- cron: '20 13 * * 1' - cron: '20 13 * * 1'
@@ -36,43 +36,42 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: [ 'javascript', 'python' ] language: ['javascript', 'python']
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file. # By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file. # Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality # queries: security-extended,security-and-quality
# 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@45775bd8235c68ba998cffa5171334d58593da47 # v3
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # ️ Command-line programs to run using the OS shell.
# If this step fails, then you should remove it and run the build manually (see below) # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# ️ Command-line programs to run using the OS shell. # If the Autobuild fails above, remove it and uncomment the following three lines.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# If the Autobuild fails above, remove it and uncomment the following three lines. # - run: |
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
# - run: | - name: Perform CodeQL Analysis
# echo "Run, Build Application using script" uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3
# ./location_of_script_within_repo/buildscript.sh with:
category: '/language:${{matrix.language}}'
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
-73
View File
@@ -1,73 +0,0 @@
# This workflow runs on certain conditions to check for and potentially
# delete container images from the GHCR which no longer have an associated
# code branch.
# Requires a PAT with the correct scope set in the secrets.
#
# This workflow will not trigger runs on forked repos.
name: Docker Cleanup
on:
pull_request:
types:
- "closed"
push:
paths:
- ".github/workflows/docker-cleanup.yml"
concurrency:
group: registry-tags-cleanup
cancel-in-progress: false
jobs:
cleanup-images:
name: Cleanup Stale Images Tags for ${{ matrix.primary-name }}
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- primary-name: "immich-server"
- primary-name: "immich-machine-learning"
env:
# Requires a personal access token with the OAuth scope delete:packages
TOKEN: ${{ secrets.PACKAGE_DELETE_TOKEN }}
steps:
- name: Clean temporary images
if: "${{ env.TOKEN != '' }}"
uses: stumpylog/image-cleaner-action/ephemeral@v0.9.0
with:
token: "${{ env.TOKEN }}"
owner: "immich-app"
is_org: "true"
do_delete: "true"
package_name: "${{ matrix.primary-name }}"
scheme: "pull_request"
repo_name: "immich"
match_regex: '^pr-(\d+)$|^(\d+)$'
cleanup-untagged-images:
name: Cleanup Untagged Images Tags for ${{ matrix.primary-name }}
runs-on: ubuntu-24.04
needs:
- cleanup-images
strategy:
fail-fast: false
matrix:
include:
- primary-name: "immich-server"
- primary-name: "immich-machine-learning"
- primary-name: "immich-build-cache"
env:
# Requires a personal access token with the OAuth scope delete:packages
TOKEN: ${{ secrets.PACKAGE_DELETE_TOKEN }}
steps:
- name: Clean untagged images
if: "${{ env.TOKEN != '' }}"
uses: stumpylog/image-cleaner-action/untagged@v0.9.0
with:
token: "${{ env.TOKEN }}"
owner: "immich-app"
do_delete: "true"
is_org: "true"
package_name: "${{ matrix.primary-name }}"
+335 -126
View File
@@ -5,7 +5,6 @@ on:
push: push:
branches: [main] branches: [main]
pull_request: pull_request:
branches: [main]
release: release:
types: [published] types: [published]
@@ -24,9 +23,9 @@ jobs:
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == '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' }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- id: found_paths - id: found_paths
uses: dorny/paths-filter@v3 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
with: with:
filters: | filters: |
server: server:
@@ -36,10 +35,12 @@ jobs:
- 'i18n/**' - 'i18n/**'
machine-learning: machine-learning:
- 'machine-learning/**' - 'machine-learning/**'
workflow:
- '.github/workflows/docker.yml'
- name: Check if we should force jobs to run - name: Check if we should force jobs to run
id: should_force id: should_force
run: echo "should_force=${{ github.event_name == 'workflow_dispatch' || github.event_name == 'release' }}" >> "$GITHUB_OUTPUT" run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'release' }}" >> "$GITHUB_OUTPUT"
retag_ml: retag_ml:
name: Re-Tag ML name: Re-Tag ML
@@ -48,21 +49,23 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
suffix: ["", "-cuda", "-openvino", "-armnn"] suffix: ['', '-cuda', '-rocm', '-openvino', '-armnn', '-rknn']
steps: steps:
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Re-tag image - name: Re-tag image
run: | run: |
REGISTRY_NAME="ghcr.io" REGISTRY_NAME="ghcr.io"
REPOSITORY=${{ github.repository_owner }}/immich-machine-learning REPOSITORY=${{ github.repository_owner }}/immich-machine-learning
TAG_OLD=main${{ matrix.suffix }} TAG_OLD=main${{ matrix.suffix }}
TAG_NEW=${{ github.event.number == 0 && github.ref_name || format('pr-{0}', github.event.number) }}${{ matrix.suffix }} TAG_PR=${{ github.event.number == 0 && github.ref_name || format('pr-{0}', github.event.number) }}${{ matrix.suffix }}
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_NEW $REGISTRY_NAME/$REPOSITORY:$TAG_OLD TAG_COMMIT=commit-${{ github.event_name != 'pull_request' && github.sha || github.event.pull_request.head.sha }}${{ matrix.suffix }}
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_PR $REGISTRY_NAME/$REPOSITORY:$TAG_OLD
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_COMMIT $REGISTRY_NAME/$REPOSITORY:$TAG_OLD
retag_server: retag_server:
name: Re-Tag Server name: Re-Tag Server
@@ -71,10 +74,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
suffix: [""] suffix: ['']
steps: steps:
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
@@ -84,107 +87,116 @@ jobs:
REGISTRY_NAME="ghcr.io" REGISTRY_NAME="ghcr.io"
REPOSITORY=${{ github.repository_owner }}/immich-server REPOSITORY=${{ github.repository_owner }}/immich-server
TAG_OLD=main${{ matrix.suffix }} TAG_OLD=main${{ matrix.suffix }}
TAG_NEW=${{ github.event.number == 0 && github.ref_name || format('pr-{0}', github.event.number) }}${{ matrix.suffix }} TAG_PR=${{ github.event.number == 0 && github.ref_name || format('pr-{0}', github.event.number) }}${{ matrix.suffix }}
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_NEW $REGISTRY_NAME/$REPOSITORY:$TAG_OLD TAG_COMMIT=commit-${{ github.event_name != 'pull_request' && github.sha || github.event.pull_request.head.sha }}${{ matrix.suffix }}
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_PR $REGISTRY_NAME/$REPOSITORY:$TAG_OLD
docker buildx imagetools create -t $REGISTRY_NAME/$REPOSITORY:$TAG_COMMIT $REGISTRY_NAME/$REPOSITORY:$TAG_OLD
build_and_push_ml: build_and_push_ml:
name: Build and Push ML name: Build and Push ML
needs: pre-job needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_ml == 'true' }} if: ${{ needs.pre-job.outputs.should_run_ml == 'true' }}
runs-on: ubuntu-latest runs-on: ${{ matrix.runner }}
env: env:
image: immich-machine-learning image: immich-machine-learning
context: machine-learning context: machine-learning
file: machine-learning/Dockerfile file: machine-learning/Dockerfile
GHCR_REPO: ghcr.io/${{ github.repository_owner }}/immich-machine-learning
strategy: strategy:
# Prevent a failure in one image from stopping the other builds # Prevent a failure in one image from stopping the other builds
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- platforms: linux/amd64,linux/arm64 - platform: linux/amd64
runner: ubuntu-latest
device: cpu device: cpu
- platforms: linux/amd64 - platform: linux/arm64
runner: ubuntu-24.04-arm
device: cpu
- platform: linux/amd64
runner: ubuntu-latest
device: cuda device: cuda
suffix: -cuda suffix: -cuda
- platforms: linux/amd64 - platform: linux/amd64
runner: mich
device: rocm
suffix: -rocm
- platform: linux/amd64
runner: ubuntu-latest
device: openvino device: openvino
suffix: -openvino suffix: -openvino
- platforms: linux/arm64 - platform: linux/arm64
runner: ubuntu-24.04-arm
device: armnn device: armnn
suffix: -armnn suffix: -armnn
steps: - platform: linux/arm64
- name: Checkout runner: ubuntu-24.04-arm
uses: actions/checkout@v4 device: rknn
suffix: -rknn
- name: Set up QEMU steps:
uses: docker/setup-qemu-action@v3.3.0 - name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.8.0 uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- name: Login to Docker Hub
# Only push to Docker Hub when making a release
if: ${{ github.event_name == 'release' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
# Skip when PR from a fork
if: ${{ !github.event.pull_request.head.repo.fork }} if: ${{ !github.event.pull_request.head.repo.fork }}
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate docker image tags - name: Generate cache key suffix
id: metadata
uses: docker/metadata-action@v5
with:
flavor: |
# Disable latest tag
latest=false
images: |
name=ghcr.io/${{ github.repository_owner }}/${{env.image}}
name=altran1502/${{env.image}},enable=${{ github.event_name == 'release' }}
tags: |
# Tag with branch name
type=ref,event=branch,suffix=${{ matrix.suffix }}
# Tag with pr-number
type=ref,event=pr,suffix=${{ matrix.suffix }}
# Tag with git tag on release
type=ref,event=tag,suffix=${{ matrix.suffix }}
type=raw,value=release,enable=${{ github.event_name == 'release' }},suffix=${{ matrix.suffix }}
- name: Determine build cache output
id: cache-target
run: | run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then if [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Essentially just ignore the cache output (PR can't write to registry cache) echo "CACHE_KEY_SUFFIX=pr-${{ github.event.number }}" >> $GITHUB_ENV
echo "cache-to=type=local,dest=/tmp/discard,ignore-error=true" >> $GITHUB_OUTPUT
else else
echo "cache-to=type=registry,mode=max,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{ env.image }}" >> $GITHUB_OUTPUT echo "CACHE_KEY_SUFFIX=$(echo ${{ github.ref_name }} | sed 's/[^a-zA-Z0-9]/-/g')" >> $GITHUB_ENV
fi fi
- name: Generate cache target
id: cache-target
run: |
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then
# Essentially just ignore the cache output (forks can't write to registry cache)
echo "cache-to=type=local,dest=/tmp/discard,ignore-error=true" >> $GITHUB_OUTPUT
else
echo "cache-to=type=registry,ref=${{ env.GHCR_REPO }}-build-cache:${{ env.PLATFORM_PAIR }}-${{ matrix.device }}-${{ env.CACHE_KEY_SUFFIX }},mode=max,compression=zstd" >> $GITHUB_OUTPUT
fi
- name: Generate docker image tags
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
env:
DOCKER_METADATA_PR_HEAD_SHA: 'true'
- name: Build and push image - name: Build and push image
uses: docker/build-push-action@v6.12.0 id: build
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
with: with:
context: ${{ env.context }} context: ${{ env.context }}
file: ${{ env.file }} file: ${{ env.file }}
platforms: ${{ matrix.platforms }} platforms: ${{ matrix.platforms }}
# Skip pushing when PR from a fork labels: ${{ steps.meta.outputs.labels }}
push: ${{ !github.event.pull_request.head.repo.fork }}
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{env.image}}
cache-to: ${{ steps.cache-target.outputs.cache-to }} cache-to: ${{ steps.cache-target.outputs.cache-to }}
tags: ${{ steps.metadata.outputs.tags }} cache-from: |
labels: ${{ steps.metadata.outputs.labels }} type=registry,ref=${{ env.GHCR_REPO }}-build-cache:${{ env.PLATFORM_PAIR }}-${{ matrix.device }}-${{ env.CACHE_KEY_SUFFIX }}
type=registry,ref=${{ env.GHCR_REPO }}-build-cache:${{ env.PLATFORM_PAIR }}-${{ matrix.device }}-main
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=${{ !github.event.pull_request.head.repo.fork }}
build-args: | build-args: |
DEVICE=${{ matrix.device }} DEVICE=${{ matrix.device }}
BUILD_ID=${{ github.run_id }} BUILD_ID=${{ github.run_id }}
@@ -192,100 +204,297 @@ jobs:
BUILD_SOURCE_REF=${{ github.ref_name }} BUILD_SOURCE_REF=${{ github.ref_name }}
BUILD_SOURCE_COMMIT=${{ github.sha }} BUILD_SOURCE_COMMIT=${{ github.sha }}
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ml-digests-${{ matrix.device }}-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge_ml:
name: Merge & Push ML
runs-on: ubuntu-latest
if: ${{ needs.pre-job.outputs.should_run_ml == 'true' && !github.event.pull_request.head.repo.fork }}
env:
GHCR_REPO: ghcr.io/${{ github.repository_owner }}/immich-machine-learning
DOCKER_REPO: altran1502/immich-machine-learning
strategy:
matrix:
include:
- device: cpu
- device: cuda
suffix: -cuda
- device: rocm
suffix: -rocm
- device: openvino
suffix: -openvino
- device: armnn
suffix: -armnn
- device: rknn
suffix: -rknn
needs:
- build_and_push_ml
steps:
- name: Download digests
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
path: ${{ runner.temp }}/digests
pattern: ml-digests-${{ matrix.device }}-*
merge-multiple: true
- name: Login to Docker Hub
if: ${{ github.event_name == 'release' }}
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
- name: Generate docker image tags
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
env:
DOCKER_METADATA_PR_HEAD_SHA: 'true'
with:
flavor: |
# Disable latest tag
latest=false
suffix=${{ matrix.suffix }}
images: |
name=${{ env.GHCR_REPO }}
name=${{ env.DOCKER_REPO }},enable=${{ github.event_name == 'release' }}
tags: |
# Tag with branch name
type=ref,event=branch
# Tag with pr-number
type=ref,event=pr
# Tag with long commit sha hash
type=sha,format=long,prefix=commit-
# Tag with git tag on release
type=ref,event=tag
type=raw,value=release,enable=${{ github.event_name == 'release' }}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
# Process annotations
declare -a ANNOTATIONS=()
if [[ -n "$DOCKER_METADATA_OUTPUT_JSON" ]]; then
while IFS= read -r annotation; do
# Extract key and value by removing the manifest: prefix
if [[ "$annotation" =~ ^manifest:(.+)=(.+)$ ]]; then
key="${BASH_REMATCH[1]}"
value="${BASH_REMATCH[2]}"
# Use array to properly handle arguments with spaces
ANNOTATIONS+=(--annotation "index:$key=$value")
fi
done < <(jq -r '.annotations[]' <<< "$DOCKER_METADATA_OUTPUT_JSON")
fi
TAGS=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
SOURCE_ARGS=$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *)
echo "docker buildx imagetools create $TAGS "${ANNOTATIONS[@]}" $SOURCE_ARGS"
docker buildx imagetools create $TAGS "${ANNOTATIONS[@]}" $SOURCE_ARGS
build_and_push_server: build_and_push_server:
name: Build and Push Server name: Build and Push Server
runs-on: ubuntu-latest runs-on: ${{ matrix.runner }}
needs: pre-job needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }} if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
env: env:
image: immich-server image: immich-server
context: . context: .
file: server/Dockerfile file: server/Dockerfile
GHCR_REPO: ghcr.io/${{ github.repository_owner }}/immich-server
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- platforms: linux/amd64,linux/arm64 - platform: linux/amd64
device: cpu runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps: steps:
- name: Checkout - name: Prepare
uses: actions/checkout@v4 run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Set up QEMU - name: Checkout
uses: docker/setup-qemu-action@v3.3.0 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.8.0 uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
- name: Login to Docker Hub
# Only push to Docker Hub when making a release
if: ${{ github.event_name == 'release' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
# Skip when PR from a fork
if: ${{ !github.event.pull_request.head.repo.fork }} if: ${{ !github.event.pull_request.head.repo.fork }}
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate docker image tags - name: Generate cache key suffix
id: metadata
uses: docker/metadata-action@v5
with:
flavor: |
# Disable latest tag
latest=false
images: |
name=ghcr.io/${{ github.repository_owner }}/${{env.image}}
name=altran1502/${{env.image}},enable=${{ github.event_name == 'release' }}
tags: |
# Tag with branch name
type=ref,event=branch,suffix=${{ matrix.suffix }}
# Tag with pr-number
type=ref,event=pr,suffix=${{ matrix.suffix }}
# Tag with git tag on release
type=ref,event=tag,suffix=${{ matrix.suffix }}
type=raw,value=release,enable=${{ github.event_name == 'release' }},suffix=${{ matrix.suffix }}
- name: Determine build cache output
id: cache-target
run: | run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then if [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Essentially just ignore the cache output (PR can't write to registry cache) echo "CACHE_KEY_SUFFIX=pr-${{ github.event.number }}" >> $GITHUB_ENV
echo "cache-to=type=local,dest=/tmp/discard,ignore-error=true" >> $GITHUB_OUTPUT
else else
echo "cache-to=type=registry,mode=max,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{ env.image }}" >> $GITHUB_OUTPUT echo "CACHE_KEY_SUFFIX=$(echo ${{ github.ref_name }} | sed 's/[^a-zA-Z0-9]/-/g')" >> $GITHUB_ENV
fi fi
- name: Generate cache target
id: cache-target
run: |
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then
# Essentially just ignore the cache output (forks can't write to registry cache)
echo "cache-to=type=local,dest=/tmp/discard,ignore-error=true" >> $GITHUB_OUTPUT
else
echo "cache-to=type=registry,ref=${{ env.GHCR_REPO }}-build-cache:${{ env.PLATFORM_PAIR }}-${{ env.CACHE_KEY_SUFFIX }},mode=max,compression=zstd" >> $GITHUB_OUTPUT
fi
- name: Generate docker image tags
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
env:
DOCKER_METADATA_PR_HEAD_SHA: 'true'
- name: Build and push image - name: Build and push image
uses: docker/build-push-action@v6.12.0 id: build
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
with: with:
context: ${{ env.context }} context: ${{ env.context }}
file: ${{ env.file }} file: ${{ env.file }}
platforms: ${{ matrix.platforms }} platforms: ${{ matrix.platform }}
# Skip pushing when PR from a fork labels: ${{ steps.meta.outputs.labels }}
push: ${{ !github.event.pull_request.head.repo.fork }}
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{env.image}}
cache-to: ${{ steps.cache-target.outputs.cache-to }} cache-to: ${{ steps.cache-target.outputs.cache-to }}
tags: ${{ steps.metadata.outputs.tags }} cache-from: |
labels: ${{ steps.metadata.outputs.labels }} type=registry,ref=${{ env.GHCR_REPO }}-build-cache:${{ env.PLATFORM_PAIR }}-${{ env.CACHE_KEY_SUFFIX }}
type=registry,ref=${{ env.GHCR_REPO }}-build-cache:${{ env.PLATFORM_PAIR }}-main
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=${{ !github.event.pull_request.head.repo.fork }}
build-args: | build-args: |
DEVICE=${{ matrix.device }} DEVICE=cpu
BUILD_ID=${{ github.run_id }} BUILD_ID=${{ github.run_id }}
BUILD_IMAGE=${{ github.event_name == 'release' && github.ref_name || steps.metadata.outputs.tags }} BUILD_IMAGE=${{ github.event_name == 'release' && github.ref_name || steps.metadata.outputs.tags }}
BUILD_SOURCE_REF=${{ github.ref_name }} BUILD_SOURCE_REF=${{ github.ref_name }}
BUILD_SOURCE_COMMIT=${{ github.sha }} BUILD_SOURCE_COMMIT=${{ github.sha }}
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: server-digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge_server:
name: Merge & Push Server
runs-on: ubuntu-latest
if: ${{ needs.pre-job.outputs.should_run_server == 'true' && !github.event.pull_request.head.repo.fork }}
env:
GHCR_REPO: ghcr.io/${{ github.repository_owner }}/immich-server
DOCKER_REPO: altran1502/immich-server
needs:
- build_and_push_server
steps:
- name: Download digests
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
path: ${{ runner.temp }}/digests
pattern: server-digests-*
merge-multiple: true
- name: Login to Docker Hub
if: ${{ github.event_name == 'release' }}
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
- name: Generate docker image tags
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
env:
DOCKER_METADATA_PR_HEAD_SHA: 'true'
with:
flavor: |
# Disable latest tag
latest=false
suffix=${{ matrix.suffix }}
images: |
name=${{ env.GHCR_REPO }}
name=${{ env.DOCKER_REPO }},enable=${{ github.event_name == 'release' }}
tags: |
# Tag with branch name
type=ref,event=branch
# Tag with pr-number
type=ref,event=pr
# Tag with long commit sha hash
type=sha,format=long,prefix=commit-
# Tag with git tag on release
type=ref,event=tag
type=raw,value=release,enable=${{ github.event_name == 'release' }}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
# Process annotations
declare -a ANNOTATIONS=()
if [[ -n "$DOCKER_METADATA_OUTPUT_JSON" ]]; then
while IFS= read -r annotation; do
# Extract key and value by removing the manifest: prefix
if [[ "$annotation" =~ ^manifest:(.+)=(.+)$ ]]; then
key="${BASH_REMATCH[1]}"
value="${BASH_REMATCH[2]}"
# Use array to properly handle arguments with spaces
ANNOTATIONS+=(--annotation "index:$key=$value")
fi
done < <(jq -r '.annotations[]' <<< "$DOCKER_METADATA_OUTPUT_JSON")
fi
TAGS=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
SOURCE_ARGS=$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *)
echo "docker buildx imagetools create $TAGS "${ANNOTATIONS[@]}" $SOURCE_ARGS"
docker buildx imagetools create $TAGS "${ANNOTATIONS[@]}" $SOURCE_ARGS
success-check-server: success-check-server:
name: Docker Build & Push Server Success name: Docker Build & Push Server Success
needs: [build_and_push_server, retag_server] needs: [merge_server, retag_server]
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: always() if: always()
steps: steps:
@@ -298,7 +507,7 @@ jobs:
success-check-ml: success-check-ml:
name: Docker Build & Push ML Success name: Docker Build & Push ML Success
needs: [build_and_push_ml, retag_ml] needs: [merge_ml, retag_ml]
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: always() if: always()
steps: steps:
+9 -8
View File
@@ -3,7 +3,6 @@ on:
push: push:
branches: [main] branches: [main]
pull_request: pull_request:
branches: [main]
release: release:
types: [published] types: [published]
@@ -15,19 +14,21 @@ jobs:
pre-job: pre-job:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.should_force.outputs.should_force == 'true' }} should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.should_force.outputs.should_force == 'true' }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- id: found_paths - id: found_paths
uses: dorny/paths-filter@v3 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
with: with:
filters: | filters: |
docs: docs:
- 'docs/**' - 'docs/**'
workflow:
- '.github/workflows/docs-build.yml'
- name: Check if we should force jobs to run - name: Check if we should force jobs to run
id: should_force id: should_force
run: echo "should_force=${{ github.event_name == 'release' || github.ref_name == 'main' }}" >> "$GITHUB_OUTPUT" run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'release' || github.ref_name == 'main' }}" >> "$GITHUB_OUTPUT"
build: build:
name: Docs Build name: Docs Build
@@ -40,10 +41,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './docs/.nvmrc' node-version-file: './docs/.nvmrc'
@@ -57,7 +58,7 @@ jobs:
run: npm run build run: npm run build
- name: Upload build output - name: Upload build output
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with: with:
name: docs-build-output name: docs-build-output
path: docs/build/ path: docs/build/
+21 -21
View File
@@ -1,7 +1,7 @@
name: Docs deploy name: Docs deploy
on: on:
workflow_run: workflow_run:
workflows: ["Docs build"] workflows: ['Docs build']
types: types:
- completed - completed
@@ -17,7 +17,7 @@ jobs:
run: echo 'The triggering workflow did not succeed' && exit 1 run: echo 'The triggering workflow did not succeed' && exit 1
- name: Get artifact - name: Get artifact
id: get-artifact id: get-artifact
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with: with:
script: | script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
@@ -35,7 +35,7 @@ jobs:
return { found: true, id: matchArtifact.id }; return { found: true, id: matchArtifact.id };
- name: Determine deploy parameters - name: Determine deploy parameters
id: parameters id: parameters
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with: with:
script: | script: |
const eventType = context.payload.workflow_run.event; const eventType = context.payload.workflow_run.event;
@@ -98,11 +98,11 @@ jobs:
if: ${{ fromJson(needs.checks.outputs.artifact).found && fromJson(needs.checks.outputs.parameters).shouldDeploy }} if: ${{ fromJson(needs.checks.outputs.artifact).found && fromJson(needs.checks.outputs.parameters).shouldDeploy }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Load parameters - name: Load parameters
id: parameters id: parameters
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with: with:
script: | script: |
const json = `${{ needs.checks.outputs.parameters }}`; const json = `${{ needs.checks.outputs.parameters }}`;
@@ -115,7 +115,7 @@ jobs:
echo "Starting docs deployment for ${{ steps.parameters.outputs.event }} ${{ steps.parameters.outputs.name }}" echo "Starting docs deployment for ${{ steps.parameters.outputs.event }} ${{ steps.parameters.outputs.name }}"
- name: Download artifact - name: Download artifact
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with: with:
script: | script: |
let artifact = ${{ needs.checks.outputs.artifact }}; let artifact = ${{ needs.checks.outputs.artifact }};
@@ -138,12 +138,12 @@ jobs:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }} TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
uses: gruntwork-io/terragrunt-action@v2 uses: gruntwork-io/terragrunt-action@9559e51d05873b0ea467c42bbabcb5c067642ccc # v2
with: with:
tg_version: "0.58.12" tg_version: '0.58.12'
tofu_version: "1.7.1" tofu_version: '1.7.1'
tg_dir: "deployment/modules/cloudflare/docs" tg_dir: 'deployment/modules/cloudflare/docs'
tg_command: "apply" tg_command: 'apply'
- name: Deploy Docs Subdomain Output - name: Deploy Docs Subdomain Output
id: docs-output id: docs-output
@@ -153,12 +153,12 @@ jobs:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }} TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
uses: gruntwork-io/terragrunt-action@v2 uses: gruntwork-io/terragrunt-action@9559e51d05873b0ea467c42bbabcb5c067642ccc # v2
with: with:
tg_version: "0.58.12" tg_version: '0.58.12'
tofu_version: "1.7.1" tofu_version: '1.7.1'
tg_dir: "deployment/modules/cloudflare/docs" tg_dir: 'deployment/modules/cloudflare/docs'
tg_command: "output -json" tg_command: 'output -json'
- name: Output Cleaning - name: Output Cleaning
id: clean id: clean
@@ -167,13 +167,13 @@ jobs:
echo "output=$TG_OUT" >> $GITHUB_OUTPUT echo "output=$TG_OUT" >> $GITHUB_OUTPUT
- name: Publish to Cloudflare Pages - name: Publish to Cloudflare Pages
uses: cloudflare/pages-action@v1 uses: cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca # v1
with: with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN_PAGES_UPLOAD }} apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN_PAGES_UPLOAD }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ${{ fromJson(steps.clean.outputs.output).pages_project_name.value }} projectName: ${{ fromJson(steps.clean.outputs.output).pages_project_name.value }}
workingDirectory: "docs" workingDirectory: 'docs'
directory: "build" directory: 'build'
branch: ${{ steps.parameters.outputs.name }} branch: ${{ steps.parameters.outputs.name }}
wranglerVersion: '3' wranglerVersion: '3'
@@ -184,7 +184,7 @@ jobs:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }} TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
uses: gruntwork-io/terragrunt-action@v2 uses: gruntwork-io/terragrunt-action@9559e51d05873b0ea467c42bbabcb5c067642ccc # v2
with: with:
tg_version: '0.58.12' tg_version: '0.58.12'
tofu_version: '1.7.1' tofu_version: '1.7.1'
@@ -192,7 +192,7 @@ jobs:
tg_command: 'apply' tg_command: 'apply'
- name: Comment - name: Comment
uses: actions-cool/maintain-one-comment@v3 uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b # v3
if: ${{ steps.parameters.outputs.event == 'pr' }} if: ${{ steps.parameters.outputs.event == 'pr' }}
with: with:
number: ${{ fromJson(needs.checks.outputs.parameters).pr_number }} number: ${{ fromJson(needs.checks.outputs.parameters).pr_number }}
+9 -9
View File
@@ -9,24 +9,24 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Destroy Docs Subdomain - name: Destroy Docs Subdomain
env: env:
TF_VAR_prefix_name: "pr-${{ github.event.number }}" TF_VAR_prefix_name: 'pr-${{ github.event.number }}'
TF_VAR_prefix_event_type: "pr" TF_VAR_prefix_event_type: 'pr'
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }} TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
uses: gruntwork-io/terragrunt-action@v2 uses: gruntwork-io/terragrunt-action@9559e51d05873b0ea467c42bbabcb5c067642ccc # v2
with: with:
tg_version: "0.58.12" tg_version: '0.58.12'
tofu_version: "1.7.1" tofu_version: '1.7.1'
tg_dir: "deployment/modules/cloudflare/docs" tg_dir: 'deployment/modules/cloudflare/docs'
tg_command: "destroy -refresh=false" tg_command: 'destroy -refresh=false'
- name: Comment - name: Comment
uses: actions-cool/maintain-one-comment@v3 uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b # v3
with: with:
number: ${{ github.event.number }} number: ${{ github.event.number }}
delete: true delete: true
+5 -6
View File
@@ -13,19 +13,19 @@ jobs:
steps: steps:
- name: Generate a token - name: Generate a token
id: generate-token id: generate-token
uses: actions/create-github-app-token@v1 uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2
with: with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: 'Checkout' - name: 'Checkout'
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
ref: ${{ github.event.pull_request.head.ref }} ref: ${{ github.event.pull_request.head.ref }}
token: ${{ steps.generate-token.outputs.token }} token: ${{ steps.generate-token.outputs.token }}
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './server/.nvmrc' node-version-file: './server/.nvmrc'
@@ -33,13 +33,13 @@ jobs:
run: make install-all && make format-all run: make install-all && make format-all
- name: Commit and push - name: Commit and push
uses: EndBug/add-and-commit@v9 uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9
with: with:
default_author: github_actions default_author: github_actions
message: 'chore: fix formatting' message: 'chore: fix formatting'
- name: Remove label - name: Remove label
uses: actions/github-script@v7 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
if: always() if: always()
with: with:
script: | script: |
@@ -49,4 +49,3 @@ jobs:
repo: context.repo.repo, repo: context.repo.repo,
name: 'fix:formatting' name: 'fix:formatting'
}) })
+3 -3
View File
@@ -12,11 +12,11 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Require PR to have a changelog label - name: Require PR to have a changelog label
uses: mheap/github-action-required-labels@v5 uses: mheap/github-action-required-labels@388fd6af37b34cdfe5a23b37060e763217e58b03 # v5
with: with:
mode: exactly mode: exactly
count: 1 count: 1
use_regex: true use_regex: true
labels: "changelog:.*" labels: 'changelog:.*'
add_comment: true add_comment: true
message: "Label error. Requires {{errorString}} {{count}} of: {{ provided }}. Found: {{ applied }}. A maintainer will add the required label." message: 'Label error. Requires {{errorString}} {{count}} of: {{ provided }}. Found: {{ applied }}. A maintainer will add the required label.'
+3 -3
View File
@@ -1,6 +1,6 @@
name: "Pull Request Labeler" name: 'Pull Request Labeler'
on: on:
- pull_request_target - pull_request_target
jobs: jobs:
labeler: labeler:
@@ -9,4 +9,4 @@ jobs:
pull-requests: write pull-requests: write
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/labeler@v5 - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: PR Conventional Commit Validation - name: PR Conventional Commit Validation
uses: ytanikin/PRConventionalCommits@1.3.0 uses: ytanikin/PRConventionalCommits@b628c5a234cc32513014b7bfdd1e47b532124d98 # 1.3.0
with: with:
task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]' task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]'
add_label: 'false' add_label: 'false'
+10 -10
View File
@@ -31,25 +31,25 @@ jobs:
steps: steps:
- name: Generate a token - name: Generate a token
id: generate-token id: generate-token
uses: actions/create-github-app-token@v1 uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2
with: with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
token: ${{ steps.generate-token.outputs.token }} token: ${{ steps.generate-token.outputs.token }}
- name: Install Poetry - name: Install uv
run: pipx install poetry uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5
- name: Bump version - name: Bump version
run: misc/release/pump-version.sh -s "${{ inputs.serverBump }}" -m "${{ inputs.mobileBump }}" run: misc/release/pump-version.sh -s "${{ inputs.serverBump }}" -m "${{ inputs.mobileBump }}"
- name: Commit and tag - name: Commit and tag
id: push-tag id: push-tag
uses: EndBug/add-and-commit@v9 uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9
with: with:
default_author: github_actions default_author: github_actions
message: 'chore: version ${{ env.IMMICH_VERSION }}' message: 'chore: version ${{ env.IMMICH_VERSION }}'
@@ -70,23 +70,23 @@ jobs:
steps: steps:
- name: Generate a token - name: Generate a token
id: generate-token id: generate-token
uses: actions/create-github-app-token@v1 uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2
with: with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
token: ${{ steps.generate-token.outputs.token }} token: ${{ steps.generate-token.outputs.token }}
- name: Download APK - name: Download APK
uses: actions/download-artifact@v4 uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with: with:
name: release-apk-signed name: release-apk-signed
- name: Create draft release - name: Create draft release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2
with: with:
draft: true draft: true
tag_name: ${{ env.IMMICH_VERSION }} tag_name: ${{ env.IMMICH_VERSION }}
+33
View File
@@ -0,0 +1,33 @@
name: Preview label
on:
pull_request:
types: [labeled, closed]
jobs:
comment-status:
runs-on: ubuntu-latest
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'preview' }}
permissions:
pull-requests: write
steps:
- uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2
with:
message-id: 'preview-status'
message: 'Deploying preview environment to https://pr-${{ github.event.pull_request.number }}.preview.internal.immich.cloud/'
remove-label:
runs-on: ubuntu-latest
if: ${{ github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'preview') }}
permissions:
pull-requests: write
steps:
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
script: |
github.rest.issues.removeLabel({
issue_number: context.payload.pull_request.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: 'preview'
})
+2 -2
View File
@@ -15,9 +15,9 @@ jobs:
run: run:
working-directory: ./open-api/typescript-sdk working-directory: ./open-api/typescript-sdk
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
# Setup .npmrc file to publish to npm # Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './open-api/typescript-sdk/.nvmrc' node-version-file: './open-api/typescript-sdk/.nvmrc'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
+31 -10
View File
@@ -16,16 +16,18 @@ jobs:
should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }} should_run: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- id: found_paths - id: found_paths
uses: dorny/paths-filter@v3 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
with: with:
filters: | filters: |
mobile: mobile:
- 'mobile/**' - 'mobile/**'
workflow:
- '.github/workflows/static_analysis.yml'
- name: Check if we should force jobs to run - name: Check if we should force jobs to run
id: should_force id: should_force
run: echo "should_force=${{ github.event_name == 'release' }}" >> "$GITHUB_OUTPUT" run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'release' }}" >> "$GITHUB_OUTPUT"
mobile-dart-analyze: mobile-dart-analyze:
name: Run Dart Code Analysis name: Run Dart Code Analysis
@@ -36,10 +38,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Flutter SDK - name: Setup Flutter SDK
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2
with: with:
channel: 'stable' channel: 'stable'
flutter-version-file: ./mobile/pubspec.yaml flutter-version-file: ./mobile/pubspec.yaml
@@ -48,6 +50,30 @@ jobs:
run: dart pub get run: dart pub get
working-directory: ./mobile working-directory: ./mobile
- name: Generate translation file
run: make translation; dart format lib/generated/codegen_loader.g.dart
working-directory: ./mobile
- name: Run Build Runner
run: make build
working-directory: ./mobile
- name: Find file changes
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20
id: verify-changed-files
with:
files: |
mobile/**/*.g.dart
mobile/**/*.gr.dart
mobile/**/*.drift.dart
- name: Verify files have not changed
if: steps.verify-changed-files.outputs.files_changed == 'true'
run: |
echo "ERROR: Generated files not up to date! Run make_build inside the mobile directory"
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}"
exit 1
- name: Run dart analyze - name: Run dart analyze
run: dart analyze --fatal-infos run: dart analyze --fatal-infos
working-directory: ./mobile working-directory: ./mobile
@@ -59,8 +85,3 @@ jobs:
- name: Run dart custom_lint - name: Run dart custom_lint
run: dart run custom_lint run: dart run custom_lint
working-directory: ./mobile working-directory: ./mobile
# Enable after riverpod generator migration is completed
# - name: Run dart custom lint
# run: dart run custom_lint
# working-directory: ./mobile
+89 -52
View File
@@ -21,11 +21,12 @@ jobs:
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == '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_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_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
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- id: found_paths - id: found_paths
uses: dorny/paths-filter@v3 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
with: with:
filters: | filters: |
web: web:
@@ -43,10 +44,14 @@ jobs:
- 'mobile/**' - 'mobile/**'
machine-learning: machine-learning:
- 'machine-learning/**' - 'machine-learning/**'
workflow:
- '.github/workflows/test.yml'
.github:
- '.github/**'
- name: Check if we should force jobs to run - name: Check if we should force jobs to run
id: should_force id: should_force
run: echo "should_force=${{ github.event_name == 'workflow_dispatch' }}" >> "$GITHUB_OUTPUT" run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'workflow_dispatch' }}" >> "$GITHUB_OUTPUT"
server-unit-tests: server-unit-tests:
name: Test & Lint Server name: Test & Lint Server
@@ -59,10 +64,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './server/.nvmrc' node-version-file: './server/.nvmrc'
@@ -96,10 +101,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './cli/.nvmrc' node-version-file: './cli/.nvmrc'
@@ -137,10 +142,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './cli/.nvmrc' node-version-file: './cli/.nvmrc'
@@ -171,10 +176,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './web/.nvmrc' node-version-file: './web/.nvmrc'
@@ -216,10 +221,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './e2e/.nvmrc' node-version-file: './e2e/.nvmrc'
@@ -244,25 +249,30 @@ jobs:
run: npm run check run: npm run check
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
medium-tests-server: server-medium-tests:
name: Medium Tests (Server) name: Medium Tests (Server)
needs: pre-job needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }} if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
runs-on: mich runs-on: ubuntu-latest
defaults:
run:
working-directory: ./server
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
submodules: 'recursive'
- name: Production build - name: Setup Node
if: ${{ !cancelled() }} uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
run: docker compose -f e2e/docker-compose.yml build with:
node-version-file: './server/.nvmrc'
- name: Run npm install
run: npm ci
- name: Run medium tests - name: Run medium tests
run: npm run test:medium
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
run: make test-medium
e2e-tests-server-cli: e2e-tests-server-cli:
name: End-to-End Tests (Server & CLI) name: End-to-End Tests (Server & CLI)
@@ -275,12 +285,12 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
submodules: 'recursive' submodules: 'recursive'
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './e2e/.nvmrc' node-version-file: './e2e/.nvmrc'
@@ -317,12 +327,12 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with: with:
submodules: 'recursive' submodules: 'recursive'
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './e2e/.nvmrc' node-version-file: './e2e/.nvmrc'
@@ -353,9 +363,9 @@ jobs:
if: ${{ needs.pre-job.outputs.should_run_mobile == 'true' }} if: ${{ needs.pre-job.outputs.should_run_mobile == 'true' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Flutter SDK - name: Setup Flutter SDK
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2
with: with:
channel: 'stable' channel: 'stable'
flutter-version-file: ./mobile/pubspec.yaml flutter-version-file: ./mobile/pubspec.yaml
@@ -372,34 +382,60 @@ jobs:
run: run:
working-directory: ./machine-learning working-directory: ./machine-learning
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Install poetry - name: Install uv
run: pipx install poetry uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5
- uses: actions/setup-python@v5 - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5
with: # TODO: add caching when supported (https://github.com/actions/setup-python/pull/818)
python-version: 3.11 # with:
cache: 'poetry' # python-version: 3.11
# cache: 'uv'
- name: Install dependencies - name: Install dependencies
run: | run: |
poetry install --with dev --with cpu uv sync --extra cpu
- name: Lint with ruff - name: Lint with ruff
run: | run: |
poetry run ruff check --output-format=github app export uv run ruff check --output-format=github immich_ml
- name: Check black formatting - name: Check black formatting
run: | run: |
poetry run black --check app export uv run black --check immich_ml
- name: Run mypy type checking - name: Run mypy type checking
run: | run: |
poetry run mypy --install-types --non-interactive --strict app/ uv run mypy --strict immich_ml/
- name: Run tests and coverage - name: Run tests and coverage
run: | run: |
poetry run pytest app --cov=app --cov-report term-missing uv run pytest --cov=immich_ml --cov-report term-missing
github-files-formatting:
name: .github Files Formatting
needs: pre-job
if: ${{ needs.pre-job.outputs['should_run_.github'] == 'true' }}
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./.github
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: './.github/.nvmrc'
- name: Run npm install
run: npm ci
- name: Run formatter
run: npm run format
if: ${{ !cancelled() }}
shellcheck: shellcheck:
name: ShellCheck name: ShellCheck
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Run ShellCheck - name: Run ShellCheck
uses: ludeeus/action-shellcheck@master uses: ludeeus/action-shellcheck@master
with: with:
@@ -413,10 +449,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './server/.nvmrc' node-version-file: './server/.nvmrc'
@@ -430,7 +466,7 @@ jobs:
run: make open-api run: make open-api
- name: Find file changes - name: Find file changes
uses: tj-actions/verify-changed-files@v20 uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20
id: verify-changed-files id: verify-changed-files
with: with:
files: | files: |
@@ -450,7 +486,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
services: services:
postgres: postgres:
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
env: env:
POSTGRES_PASSWORD: postgres POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres POSTGRES_USER: postgres
@@ -468,10 +504,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: './server/.nvmrc' node-version-file: './server/.nvmrc'
@@ -482,26 +518,27 @@ jobs:
run: npm run build run: npm run build
- name: Run existing migrations - name: Run existing migrations
run: npm run typeorm:migrations:run run: npm run migrations:run
- name: Test npm run schema:reset command works - name: Test npm run schema:reset command works
run: npm run typeorm:schema:reset run: npm run typeorm:schema:reset
- name: Generate new migrations - name: Generate new migrations
continue-on-error: true continue-on-error: true
run: npm run typeorm:migrations:generate ./src/migrations/TestMigration run: npm run migrations:generate TestMigration
- name: Find file changes - name: Find file changes
uses: tj-actions/verify-changed-files@v20 uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20
id: verify-changed-files id: verify-changed-files
with: with:
files: | files: |
server/src/migrations/ server/src
- name: Verify migration files have not changed - name: Verify migration files have not changed
if: steps.verify-changed-files.outputs.files_changed == 'true' if: steps.verify-changed-files.outputs.files_changed == 'true'
run: | run: |
echo "ERROR: Generated migration files not up to date!" echo "ERROR: Generated migration files not up to date!"
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}" echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}"
cat ./src/*-TestMigration.ts
exit 1 exit 1
- name: Run SQL generation - name: Run SQL generation
@@ -510,7 +547,7 @@ jobs:
DB_URL: postgres://postgres:postgres@localhost:5432/immich DB_URL: postgres://postgres:postgres@localhost:5432/immich
- name: Find file changes - name: Find file changes
uses: tj-actions/verify-changed-files@v20 uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20
id: verify-changed-sql-files id: verify-changed-sql-files
with: with:
files: | files: |
+57
View File
@@ -0,0 +1,57 @@
name: Weblate checks
on:
pull_request:
branches: [main]
jobs:
pre-job:
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.found_paths.outputs.i18n == 'true' && github.head_ref != 'chore/translations'}}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- id: found_paths
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
with:
filters: |
i18n:
- 'i18n/!(en)**\.json'
- name: Debug
run: |
echo "Should run: ${{ steps.found_paths.outputs.i18n == 'true' && github.head_ref != 'chore/translations'}}"
echo "Found i18n paths: ${{ steps.found_paths.outputs.i18n }}"
echo "Head ref: ${{ github.head_ref }}"
enforce-lock:
name: Check Weblate Lock
needs: [pre-job]
runs-on: ubuntu-latest
if: ${{ needs.pre-job.outputs.should_run == 'true' }}
steps:
- name: Check weblate lock
run: |
if [[ "false" = $(curl https://hosted.weblate.org/api/components/immich/immich/lock/ | jq .locked) ]]; then
exit 1
fi
- name: Find Pull Request
uses: juliangruber/find-pull-request-action@48b6133aa6c826f267ebd33aa2d29470f9d9e7d0 # v1
id: find-pr
with:
branch: chore/translations
- name: Fail if existing weblate PR
if: ${{ steps.find-pr.outputs.number }}
run: exit 1
success-check-lock:
name: Weblate Lock Check Success
needs: [enforce-lock]
runs-on: ubuntu-latest
if: always()
steps:
- name: Any jobs failed?
if: ${{ contains(needs.*.result, 'failure') }}
run: exit 1
- name: All jobs passed or skipped
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: echo "All jobs passed or skipped" && echo "${{ toJSON(needs.*.result) }}"
+2 -1
View File
@@ -39,6 +39,7 @@
], ],
"explorer.fileNesting.enabled": true, "explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": { "explorer.fileNesting.patterns": {
"*.ts": "${capture}.spec.ts,${capture}.mock.ts" "*.ts": "${capture}.spec.ts,${capture}.mock.ts",
"*.dart": "${capture}.g.dart,${capture}.gr.dart,${capture}.drift.dart"
} }
} }
+5 -5
View File
@@ -39,7 +39,7 @@ attach-server:
renovate: renovate:
LOG_LEVEL=debug npx renovate --platform=local --repository-cache=reset LOG_LEVEL=debug npx renovate --platform=local --repository-cache=reset
MODULES = e2e server web cli sdk docs MODULES = e2e server web cli sdk docs .github
audit-%: audit-%:
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
@@ -77,14 +77,14 @@ test-medium:
test-medium-dev: test-medium-dev:
docker exec -it immich_server /bin/sh -c "npm run test:medium" docker exec -it immich_server /bin/sh -c "npm run test:medium"
build-all: $(foreach M,$(filter-out e2e,$(MODULES)),build-$M) ; build-all: $(foreach M,$(filter-out e2e .github,$(MODULES)),build-$M) ;
install-all: $(foreach M,$(MODULES),install-$M) ; install-all: $(foreach M,$(MODULES),install-$M) ;
check-all: $(foreach M,$(filter-out sdk cli docs,$(MODULES)),check-$M) ; check-all: $(foreach M,$(filter-out sdk cli docs .github,$(MODULES)),check-$M) ;
lint-all: $(foreach M,$(filter-out sdk docs,$(MODULES)),lint-$M) ; lint-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),lint-$M) ;
format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ; format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ;
audit-all: $(foreach M,$(MODULES),audit-$M) ; audit-all: $(foreach M,$(MODULES),audit-$M) ;
hygiene-all: lint-all format-all check-all sql audit-all; hygiene-all: lint-all format-all check-all sql audit-all;
test-all: $(foreach M,$(filter-out sdk docs,$(MODULES)),test-$M) ; test-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),test-$M) ;
clean: clean:
find . -name "node_modules" -type d -prune -exec rm -rf '{}' + find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
+5 -7
View File
@@ -1,11 +1,11 @@
<p align="center"> <p align="center">
<br/> <br/>
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a> <a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
<a href="https://discord.immich.app"> <a href="https://discord.immich.app">
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/> <img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
</a> </a>
<br/> <br/>
<br/> <br/>
</p> </p>
<p align="center"> <p align="center">
@@ -61,9 +61,7 @@
## Demo ## Demo
Access the demo [here](https://demo.immich.app). The demo is running on a Free-tier Oracle VM in Amsterdam with a 2.4Ghz quad-core ARM64 CPU and 24GB RAM. Access the demo [here](https://demo.immich.app). For the mobile app, you can use `https://demo.immich.app` for the `Server Endpoint URL`.
For the mobile app, you can use `https://demo.immich.app/api` for the `Server Endpoint URL`
### Login credentials ### Login credentials
@@ -104,7 +102,7 @@ For the mobile app, you can use `https://demo.immich.app/api` for the `Server En
| Read-only gallery | Yes | Yes | | Read-only gallery | Yes | Yes |
| Stacked Photos | Yes | Yes | | Stacked Photos | Yes | Yes |
| Tags | No | Yes | | Tags | No | Yes |
| Folder View | No | Yes | | Folder View | Yes | Yes |
## Translations ## Translations
+1 -1
View File
@@ -1 +1 @@
22.13.1 22.14.0
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:22.13.1-alpine3.20@sha256:c52e20859a92b3eccbd3a36c5e1a90adc20617d8d421d65e8a622e87b5dac963 AS core FROM node:22.14.0-alpine3.20@sha256:40be979442621049f40b1d51a26b55e281246b5de4e5f51a18da7beb6e17e3f9 AS core
WORKDIR /usr/src/open-api/typescript-sdk WORKDIR /usr/src/open-api/typescript-sdk
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./ COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
+10 -20
View File
@@ -1,39 +1,29 @@
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js'; import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin'; import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import tsParser from '@typescript-eslint/parser'; import eslintPluginUnicorn from 'eslint-plugin-unicorn';
import globals from 'globals'; import globals from 'globals';
import path from 'node:path'; import path from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import typescriptEslint from 'typescript-eslint';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [ export default typescriptEslint.config([
eslintPluginUnicorn.configs.recommended,
eslintPluginPrettierRecommended,
js.configs.recommended,
typescriptEslint.configs.recommended,
{ {
ignores: ['eslint.config.mjs', 'dist'], ignores: ['eslint.config.mjs', 'dist'],
}, },
...compat.extends(
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'plugin:unicorn/recommended',
),
{ {
plugins: {
'@typescript-eslint': typescriptEslint,
},
languageOptions: { languageOptions: {
globals: { globals: {
...globals.node, ...globals.node,
}, },
parser: tsParser, parser: typescriptEslint.parser,
ecmaVersion: 5, ecmaVersion: 5,
sourceType: 'module', sourceType: 'module',
@@ -58,4 +48,4 @@ export default [
'object-shorthand': ['error', 'always'], 'object-shorthand': ['error', 'always'],
}, },
}, },
]; ]);
+1066 -1083
View File
File diff suppressed because it is too large Load Diff
+10 -8
View File
@@ -1,6 +1,6 @@
{ {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.47", "version": "2.2.61",
"description": "Command Line Interface (CLI) for Immich", "description": "Command Line Interface (CLI) for Immich",
"type": "module", "type": "module",
"exports": "./dist/index.js", "exports": "./dist/index.js",
@@ -19,10 +19,9 @@
"@types/byte-size": "^8.1.0", "@types/byte-size": "^8.1.0",
"@types/cli-progress": "^3.11.0", "@types/cli-progress": "^3.11.0",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/micromatch": "^4.0.9",
"@types/mock-fs": "^4.13.1", "@types/mock-fs": "^4.13.1",
"@types/node": "^22.10.9", "@types/node": "^22.14.0",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"@typescript-eslint/parser": "^8.15.0",
"@vitest/coverage-v8": "^3.0.0", "@vitest/coverage-v8": "^3.0.0",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"cli-progress": "^3.12.0", "cli-progress": "^3.12.0",
@@ -30,12 +29,13 @@
"eslint": "^9.14.0", "eslint": "^9.14.0",
"eslint-config-prettier": "^10.0.0", "eslint-config-prettier": "^10.0.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^56.0.1", "eslint-plugin-unicorn": "^57.0.0",
"globals": "^15.9.0", "globals": "^16.0.0",
"mock-fs": "^5.2.0", "mock-fs": "^5.2.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^4.0.0", "prettier-plugin-organize-imports": "^4.0.0",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"typescript-eslint": "^8.28.0",
"vite": "^6.0.0", "vite": "^6.0.0",
"vite-tsconfig-paths": "^5.0.0", "vite-tsconfig-paths": "^5.0.0",
"vitest": "^3.0.0", "vitest": "^3.0.0",
@@ -62,11 +62,13 @@
"node": ">=20.0.0" "node": ">=20.0.0"
}, },
"dependencies": { "dependencies": {
"chokidar": "^4.0.3",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"fastq": "^1.17.1", "fastq": "^1.17.1",
"lodash-es": "^4.17.21" "lodash-es": "^4.17.21",
"micromatch": "^4.0.8"
}, },
"volta": { "volta": {
"node": "22.13.1" "node": "22.14.0"
} }
} }
+113 -3
View File
@@ -1,12 +1,13 @@
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as os from 'node:os'; import * as os from 'node:os';
import * as path from 'node:path'; import * as path from 'node:path';
import { describe, expect, it, vi } from 'vitest'; import { setTimeout as sleep } from 'node:timers/promises';
import { describe, expect, it, MockedFunction, vi } from 'vitest';
import { Action, checkBulkUpload, defaults, Reason } from '@immich/sdk'; import { Action, checkBulkUpload, defaults, getSupportedMediaTypes, Reason } from '@immich/sdk';
import createFetchMock from 'vitest-fetch-mock'; import createFetchMock from 'vitest-fetch-mock';
import { checkForDuplicates, getAlbumName, uploadFiles, UploadOptionsDto } from './asset'; import { checkForDuplicates, getAlbumName, startWatch, uploadFiles, UploadOptionsDto } from 'src/commands/asset';
vi.mock('@immich/sdk'); vi.mock('@immich/sdk');
@@ -199,3 +200,112 @@ describe('checkForDuplicates', () => {
}); });
}); });
}); });
describe('startWatch', () => {
let testFolder: string;
let checkBulkUploadMocked: MockedFunction<typeof checkBulkUpload>;
beforeEach(async () => {
vi.restoreAllMocks();
vi.mocked(getSupportedMediaTypes).mockResolvedValue({
image: ['.jpg'],
sidecar: ['.xmp'],
video: ['.mp4'],
});
testFolder = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'test-startWatch-'));
checkBulkUploadMocked = vi.mocked(checkBulkUpload);
checkBulkUploadMocked.mockResolvedValue({
results: [],
});
});
it('should start watching a directory and upload new files', async () => {
const testFilePath = path.join(testFolder, 'test.jpg');
await startWatch([testFolder], { concurrency: 1 }, { batchSize: 1, debounceTimeMs: 10 });
await sleep(100); // to debounce the watcher from considering the test file as a existing file
await fs.promises.writeFile(testFilePath, 'testjpg');
await vi.waitUntil(() => checkBulkUploadMocked.mock.calls.length > 0, 3000);
expect(checkBulkUpload).toHaveBeenCalledWith({
assetBulkUploadCheckDto: {
assets: [
expect.objectContaining({
id: testFilePath,
}),
],
},
});
});
it('should filter out unsupported files', async () => {
const testFilePath = path.join(testFolder, 'test.jpg');
const unsupportedFilePath = path.join(testFolder, 'test.txt');
await startWatch([testFolder], { concurrency: 1 }, { batchSize: 1, debounceTimeMs: 10 });
await sleep(100); // to debounce the watcher from considering the test file as a existing file
await fs.promises.writeFile(testFilePath, 'testjpg');
await fs.promises.writeFile(unsupportedFilePath, 'testtxt');
await vi.waitUntil(() => checkBulkUploadMocked.mock.calls.length > 0, 3000);
expect(checkBulkUpload).toHaveBeenCalledWith({
assetBulkUploadCheckDto: {
assets: expect.arrayContaining([
expect.objectContaining({
id: testFilePath,
}),
]),
},
});
expect(checkBulkUpload).not.toHaveBeenCalledWith({
assetBulkUploadCheckDto: {
assets: expect.arrayContaining([
expect.objectContaining({
id: unsupportedFilePath,
}),
]),
},
});
});
it('should filger out ignored patterns', async () => {
const testFilePath = path.join(testFolder, 'test.jpg');
const ignoredPattern = 'ignored';
const ignoredFolder = path.join(testFolder, ignoredPattern);
await fs.promises.mkdir(ignoredFolder, { recursive: true });
const ignoredFilePath = path.join(ignoredFolder, 'ignored.jpg');
await startWatch([testFolder], { concurrency: 1, ignore: ignoredPattern }, { batchSize: 1, debounceTimeMs: 10 });
await sleep(100); // to debounce the watcher from considering the test file as a existing file
await fs.promises.writeFile(testFilePath, 'testjpg');
await fs.promises.writeFile(ignoredFilePath, 'ignoredjpg');
await vi.waitUntil(() => checkBulkUploadMocked.mock.calls.length > 0, 3000);
expect(checkBulkUpload).toHaveBeenCalledWith({
assetBulkUploadCheckDto: {
assets: expect.arrayContaining([
expect.objectContaining({
id: testFilePath,
}),
]),
},
});
expect(checkBulkUpload).not.toHaveBeenCalledWith({
assetBulkUploadCheckDto: {
assets: expect.arrayContaining([
expect.objectContaining({
id: ignoredFilePath,
}),
]),
},
});
});
afterEach(async () => {
await fs.promises.rm(testFolder, { recursive: true, force: true });
});
});
+125 -26
View File
@@ -12,13 +12,18 @@ import {
getSupportedMediaTypes, getSupportedMediaTypes,
} from '@immich/sdk'; } from '@immich/sdk';
import byteSize from 'byte-size'; import byteSize from 'byte-size';
import { Matcher, watch as watchFs } from 'chokidar';
import { MultiBar, Presets, SingleBar } from 'cli-progress'; import { MultiBar, Presets, SingleBar } from 'cli-progress';
import { chunk } from 'lodash-es'; import { chunk } from 'lodash-es';
import micromatch from 'micromatch';
import { Stats, createReadStream } from 'node:fs'; import { Stats, createReadStream } from 'node:fs';
import { stat, unlink } from 'node:fs/promises'; import { stat, unlink } from 'node:fs/promises';
import path, { basename } from 'node:path'; import path, { basename } from 'node:path';
import { Queue } from 'src/queue'; import { Queue } from 'src/queue';
import { BaseOptions, authenticate, crawl, sha1 } from 'src/utils'; import { BaseOptions, Batcher, authenticate, crawl, sha1 } from 'src/utils';
const UPLOAD_WATCH_BATCH_SIZE = 100;
const UPLOAD_WATCH_DEBOUNCE_TIME_MS = 10_000;
const s = (count: number) => (count === 1 ? '' : 's'); const s = (count: number) => (count === 1 ? '' : 's');
@@ -36,6 +41,8 @@ export interface UploadOptionsDto {
albumName?: string; albumName?: string;
includeHidden?: boolean; includeHidden?: boolean;
concurrency: number; concurrency: number;
progress?: boolean;
watch?: boolean;
} }
class UploadFile extends File { class UploadFile extends File {
@@ -55,19 +62,94 @@ class UploadFile extends File {
} }
} }
const uploadBatch = async (files: string[], options: UploadOptionsDto) => {
const { newFiles, duplicates } = await checkForDuplicates(files, options);
const newAssets = await uploadFiles(newFiles, options);
await updateAlbums([...newAssets, ...duplicates], options);
await deleteFiles(newFiles, options);
};
export const startWatch = async (
paths: string[],
options: UploadOptionsDto,
{
batchSize = UPLOAD_WATCH_BATCH_SIZE,
debounceTimeMs = UPLOAD_WATCH_DEBOUNCE_TIME_MS,
}: { batchSize?: number; debounceTimeMs?: number } = {},
) => {
const watcherIgnored: Matcher[] = [];
const { image, video } = await getSupportedMediaTypes();
const extensions = new Set([...image, ...video]);
if (options.ignore) {
watcherIgnored.push((path) => micromatch.contains(path, `**/${options.ignore}`));
}
const pathsBatcher = new Batcher<string>({
batchSize,
debounceTimeMs,
onBatch: async (paths: string[]) => {
const uniquePaths = [...new Set(paths)];
await uploadBatch(uniquePaths, options);
},
});
const onFile = async (path: string, stats?: Stats) => {
if (stats?.isDirectory()) {
return;
}
const ext = '.' + path.split('.').pop()?.toLowerCase();
if (!ext || !extensions.has(ext)) {
return;
}
if (!options.progress) {
// logging when progress is disabled as it can cause issues with the progress bar rendering
console.log(`Change detected: ${path}`);
}
pathsBatcher.add(path);
};
const fsWatcher = watchFs(paths, {
ignoreInitial: true,
ignored: watcherIgnored,
alwaysStat: true,
awaitWriteFinish: true,
depth: options.recursive ? undefined : 1,
persistent: true,
})
.on('add', onFile)
.on('change', onFile)
.on('error', (error) => console.error(`Watcher error: ${error}`));
process.on('SIGINT', async () => {
console.log('Exiting...');
await fsWatcher.close();
process.exit();
});
};
export const upload = async (paths: string[], baseOptions: BaseOptions, options: UploadOptionsDto) => { export const upload = async (paths: string[], baseOptions: BaseOptions, options: UploadOptionsDto) => {
await authenticate(baseOptions); await authenticate(baseOptions);
const scanFiles = await scan(paths, options); const scanFiles = await scan(paths, options);
if (scanFiles.length === 0) { if (scanFiles.length === 0) {
console.log('No files found, exiting'); if (options.watch) {
return; console.log('No files found initially.');
} else {
console.log('No files found, exiting');
return;
}
} }
const { newFiles, duplicates } = await checkForDuplicates(scanFiles, options); if (options.watch) {
const newAssets = await uploadFiles(newFiles, options); console.log('Watching for changes...');
await updateAlbums([...newAssets, ...duplicates], options); await startWatch(paths, options);
await deleteFiles(newFiles, options); // watcher does not handle the initial scan
// as the scan() is a more efficient quick start with batched results
}
await uploadBatch(scanFiles, options);
}; };
const scan = async (pathsToCrawl: string[], options: UploadOptionsDto) => { const scan = async (pathsToCrawl: string[], options: UploadOptionsDto) => {
@@ -85,19 +167,25 @@ const scan = async (pathsToCrawl: string[], options: UploadOptionsDto) => {
return files; return files;
}; };
export const checkForDuplicates = async (files: string[], { concurrency, skipHash }: UploadOptionsDto) => { export const checkForDuplicates = async (files: string[], { concurrency, skipHash, progress }: UploadOptionsDto) => {
if (skipHash) { if (skipHash) {
console.log('Skipping hash check, assuming all files are new'); console.log('Skipping hash check, assuming all files are new');
return { newFiles: files, duplicates: [] }; return { newFiles: files, duplicates: [] };
} }
const multiBar = new MultiBar( let multiBar: MultiBar | undefined;
{ format: '{message} | {bar} | {percentage}% | ETA: {eta}s | {value}/{total} assets' },
Presets.shades_classic,
);
const hashProgressBar = multiBar.create(files.length, 0, { message: 'Hashing files ' }); if (progress) {
const checkProgressBar = multiBar.create(files.length, 0, { message: 'Checking for duplicates' }); multiBar = new MultiBar(
{ format: '{message} | {bar} | {percentage}% | ETA: {eta}s | {value}/{total} assets' },
Presets.shades_classic,
);
} else {
console.log(`Received ${files.length} files, hashing...`);
}
const hashProgressBar = multiBar?.create(files.length, 0, { message: 'Hashing files ' });
const checkProgressBar = multiBar?.create(files.length, 0, { message: 'Checking for duplicates' });
const newFiles: string[] = []; const newFiles: string[] = [];
const duplicates: Asset[] = []; const duplicates: Asset[] = [];
@@ -117,7 +205,7 @@ export const checkForDuplicates = async (files: string[], { concurrency, skipHas
} }
} }
checkProgressBar.increment(assets.length); checkProgressBar?.increment(assets.length);
}, },
{ concurrency, retry: 3 }, { concurrency, retry: 3 },
); );
@@ -137,7 +225,7 @@ export const checkForDuplicates = async (files: string[], { concurrency, skipHas
void checkBulkUploadQueue.push(batch); void checkBulkUploadQueue.push(batch);
} }
hashProgressBar.increment(); hashProgressBar?.increment();
return results; return results;
}, },
{ concurrency, retry: 3 }, { concurrency, retry: 3 },
@@ -155,7 +243,7 @@ export const checkForDuplicates = async (files: string[], { concurrency, skipHas
await checkBulkUploadQueue.drained(); await checkBulkUploadQueue.drained();
multiBar.stop(); multiBar?.stop();
console.log(`Found ${newFiles.length} new files and ${duplicates.length} duplicate${s(duplicates.length)}`); console.log(`Found ${newFiles.length} new files and ${duplicates.length} duplicate${s(duplicates.length)}`);
@@ -171,7 +259,10 @@ export const checkForDuplicates = async (files: string[], { concurrency, skipHas
return { newFiles, duplicates }; return { newFiles, duplicates };
}; };
export const uploadFiles = async (files: string[], { dryRun, concurrency }: UploadOptionsDto): Promise<Asset[]> => { export const uploadFiles = async (
files: string[],
{ dryRun, concurrency, progress }: UploadOptionsDto,
): Promise<Asset[]> => {
if (files.length === 0) { if (files.length === 0) {
console.log('All assets were already uploaded, nothing to do.'); console.log('All assets were already uploaded, nothing to do.');
return []; return [];
@@ -191,12 +282,20 @@ export const uploadFiles = async (files: string[], { dryRun, concurrency }: Uplo
return files.map((filepath) => ({ id: '', filepath })); return files.map((filepath) => ({ id: '', filepath }));
} }
const uploadProgress = new SingleBar( let uploadProgress: SingleBar | undefined;
{ format: 'Uploading assets | {bar} | {percentage}% | ETA: {eta_formatted} | {value_formatted}/{total_formatted}' },
Presets.shades_classic, if (progress) {
); uploadProgress = new SingleBar(
uploadProgress.start(totalSize, 0); {
uploadProgress.update({ value_formatted: 0, total_formatted: byteSize(totalSize) }); format: 'Uploading assets | {bar} | {percentage}% | ETA: {eta_formatted} | {value_formatted}/{total_formatted}',
},
Presets.shades_classic,
);
} else {
console.log(`Uploading ${files.length} asset${s(files.length)} (${byteSize(totalSize)})`);
}
uploadProgress?.start(totalSize, 0);
uploadProgress?.update({ value_formatted: 0, total_formatted: byteSize(totalSize) });
let duplicateCount = 0; let duplicateCount = 0;
let duplicateSize = 0; let duplicateSize = 0;
@@ -222,7 +321,7 @@ export const uploadFiles = async (files: string[], { dryRun, concurrency }: Uplo
successSize += stats.size ?? 0; successSize += stats.size ?? 0;
} }
uploadProgress.update(successSize, { value_formatted: byteSize(successSize + duplicateSize) }); uploadProgress?.update(successSize, { value_formatted: byteSize(successSize + duplicateSize) });
return response; return response;
}, },
@@ -235,7 +334,7 @@ export const uploadFiles = async (files: string[], { dryRun, concurrency }: Uplo
await queue.drained(); await queue.drained();
uploadProgress.stop(); uploadProgress?.stop();
console.log(`Successfully uploaded ${successCount} new asset${s(successCount)} (${byteSize(successSize)})`); console.log(`Successfully uploaded ${successCount} new asset${s(successCount)} (${byteSize(successSize)})`);
if (duplicateCount > 0) { if (duplicateCount > 0) {
+7
View File
@@ -69,6 +69,13 @@ program
.default(4), .default(4),
) )
.addOption(new Option('--delete', 'Delete local assets after upload').env('IMMICH_DELETE_ASSETS')) .addOption(new Option('--delete', 'Delete local assets after upload').env('IMMICH_DELETE_ASSETS'))
.addOption(new Option('--no-progress', 'Hide progress bars').env('IMMICH_PROGRESS_BAR').default(true))
.addOption(
new Option('--watch', 'Watch for changes and upload automatically')
.env('IMMICH_WATCH_CHANGES')
.default(false)
.implies({ progress: false }),
)
.argument('[paths...]', 'One or more paths to assets to be uploaded') .argument('[paths...]', 'One or more paths to assets to be uploaded')
.action((paths, options) => upload(paths, program.opts(), options)); .action((paths, options) => upload(paths, program.opts(), options));
+37 -1
View File
@@ -1,6 +1,7 @@
import mockfs from 'mock-fs'; import mockfs from 'mock-fs';
import { readFileSync } from 'node:fs'; import { readFileSync } from 'node:fs';
import { CrawlOptions, crawl } from 'src/utils'; import { Batcher, CrawlOptions, crawl } from 'src/utils';
import { Mock } from 'vitest';
interface Test { interface Test {
test: string; test: string;
@@ -303,3 +304,38 @@ describe('crawl', () => {
} }
}); });
}); });
describe('Batcher', () => {
let batcher: Batcher;
let onBatch: Mock;
beforeEach(() => {
onBatch = vi.fn();
batcher = new Batcher({ batchSize: 2, onBatch });
});
it('should trigger onBatch() when a batch limit is reached', async () => {
batcher.add('a');
batcher.add('b');
batcher.add('c');
expect(onBatch).toHaveBeenCalledOnce();
expect(onBatch).toHaveBeenCalledWith(['a', 'b']);
});
it('should trigger onBatch() when flush() is called', async () => {
batcher.add('a');
batcher.flush();
expect(onBatch).toHaveBeenCalledOnce();
expect(onBatch).toHaveBeenCalledWith(['a']);
});
it('should trigger onBatch() when debounce time reached', async () => {
vi.useFakeTimers();
batcher = new Batcher({ batchSize: 2, debounceTimeMs: 100, onBatch });
batcher.add('a');
expect(onBatch).not.toHaveBeenCalled();
vi.advanceTimersByTime(200);
expect(onBatch).toHaveBeenCalledOnce();
expect(onBatch).toHaveBeenCalledWith(['a']);
vi.useRealTimers();
});
});
+61
View File
@@ -172,3 +172,64 @@ export const sha1 = (filepath: string) => {
rs.on('end', () => resolve(hash.digest('hex'))); rs.on('end', () => resolve(hash.digest('hex')));
}); });
}; };
/**
* Batches items and calls onBatch to process them
* when the batch size is reached or the debounce time has passed.
*/
export class Batcher<T = unknown> {
private items: T[] = [];
private readonly batchSize: number;
private readonly debounceTimeMs?: number;
private readonly onBatch: (items: T[]) => void;
private debounceTimer?: NodeJS.Timeout;
constructor({
batchSize,
debounceTimeMs,
onBatch,
}: {
batchSize: number;
debounceTimeMs?: number;
onBatch: (items: T[]) => Promise<void>;
}) {
this.batchSize = batchSize;
this.debounceTimeMs = debounceTimeMs;
this.onBatch = onBatch;
}
private setDebounceTimer() {
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
if (this.debounceTimeMs) {
this.debounceTimer = setTimeout(() => this.flush(), this.debounceTimeMs);
}
}
private clearDebounceTimer() {
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = undefined;
}
}
add(item: T) {
this.items.push(item);
this.setDebounceTimer();
if (this.items.length >= this.batchSize) {
this.flush();
}
}
flush() {
this.clearDebounceTimer();
if (this.items.length === 0) {
return;
}
this.onBatch(this.items);
this.items = [];
}
}
+30 -30
View File
@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates. # Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" { provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.50.0" version = "4.52.0"
constraints = "4.50.0" constraints = "4.52.0"
hashes = [ hashes = [
"h1:0qvD5ZKn2tMZ8cOjQrUSITIC9tKCZbrSaSswV9lOyiU=", "h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=",
"h1:4N0gplrZ0zOsJv3Kx1VfIx2FwrZHbYU0Un2yfiLZIGQ=", "h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=",
"h1:81AMQq4kNKU/35U8ElQegUxG4E6xB0erIjG5xVmjIyo=", "h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=",
"h1:EEQNADUmV3IL6x00yzy04i7OCSLeOMgM9XQkV3w71gA=", "h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=",
"h1:HD0KI7td6oiSSAnJNn8UPSGf+hKiTo4JVQYfAiU1SqM=", "h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=",
"h1:Hl+o5LtcvZg2f3l1hh9vaG/DFK6k+dTIZSeM0lXyfpo=", "h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=",
"h1:ZUO2oIJ6jtZdvl816h0cEIiIeZ/fFCF64+abGEVxZZM=", "h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=",
"h1:Zio80fnEeUKdlSOhTVskMEFSLUQ6TMsMKnXc+Dy2P2A=", "h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=",
"h1:aLLvg36evTyqjtXGV2MjAV8imktXFmry7p/xCu9GQC4=", "h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=",
"h1:azL05eWyy2V8SWkbZZImPWvv8ynG4eqmrbZhjXBDFug=", "h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=",
"h1:ckMysHY4fJmr7o58XMi+DdgOTB/U/Mf1u1JA9ly3g/I=", "h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=",
"h1:jxOwjDNjt5WCb4YjjiMsman91O8Y+MAPz6UwJ4a6F+0=", "h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=",
"h1:u4OfnjSLa4Wk1IUFAzrvMnGgr8MvRHEWVDHEScPK2E8=", "h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=",
"h1:wQkR1oeSkzlHn3rnVuLJRJLBHlg4EHt7Y64DeTjfkjQ=", "h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=",
"zh:0ef99ed39472a94e6a0d6fa733cf0a46bce3bf66eba2873efae8846efdddc237", "zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0",
"zh:2929cbbffcead171d45c88e4a7a59e9c013ea775dafa68b10da8db7cd04b6140", "zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8",
"zh:462601c87118088e1a718842e367af7d8e7620598d426980a6d6b33de759865e", "zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238",
"zh:56766eb62a74a9d88d9efb8486dd3a0c5c9db873d0a980ae9ef1e8af27d74231", "zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f",
"zh:6b4e8810d99498a5a20a5872982a0f1354e79cfc4a7dfe7cc656f1c7eaae47d8", "zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f",
"zh:6d65bdb4ec94b6eecc8abe26d94e2ca09262dc1e7a9934db829f418be0119920", "zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8",
"zh:71adeaf31e41a358ec6095004062e43f56ee7d4b2504e5613ab351d511695641", "zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9",
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:89761c15908ccc2cf9c50bb5cb3be45d3ad0c45fc7c608c6b95f48c0288b7160", "zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6",
"zh:8cc5d7c5939da89cfd01f3e51c84f3576564783acea9db86bd9e32049805ed96", "zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb",
"zh:987cff8225b1dd436cdcb4fc6228689ae7e4281de6896412a2a9a3325c49f05e", "zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b",
"zh:991e83ebb89867d71e01a1c215ed159efb425683b0a44707be8579eb0a337f06", "zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380",
"zh:ab8177ae2d8f5cfa90043a6f867435012cae115f6061b832a7e2462e0ae87a67", "zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7",
"zh:d1ca34df1398f201274a6a18102975148c10ca15aa43cfc56cc9897620929509", "zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
"zh:d34946f70201baf6dda03e3b294c6bbe40d95d0278e97b9f636ded94822b24ac",
] ]
} }
@@ -5,7 +5,7 @@ terraform {
required_providers { required_providers {
cloudflare = { cloudflare = {
source = "cloudflare/cloudflare" source = "cloudflare/cloudflare"
version = "4.50.0" version = "4.52.0"
} }
} }
} }
+30 -30
View File
@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates. # Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" { provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.50.0" version = "4.52.0"
constraints = "4.50.0" constraints = "4.52.0"
hashes = [ hashes = [
"h1:0qvD5ZKn2tMZ8cOjQrUSITIC9tKCZbrSaSswV9lOyiU=", "h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=",
"h1:4N0gplrZ0zOsJv3Kx1VfIx2FwrZHbYU0Un2yfiLZIGQ=", "h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=",
"h1:81AMQq4kNKU/35U8ElQegUxG4E6xB0erIjG5xVmjIyo=", "h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=",
"h1:EEQNADUmV3IL6x00yzy04i7OCSLeOMgM9XQkV3w71gA=", "h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=",
"h1:HD0KI7td6oiSSAnJNn8UPSGf+hKiTo4JVQYfAiU1SqM=", "h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=",
"h1:Hl+o5LtcvZg2f3l1hh9vaG/DFK6k+dTIZSeM0lXyfpo=", "h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=",
"h1:ZUO2oIJ6jtZdvl816h0cEIiIeZ/fFCF64+abGEVxZZM=", "h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=",
"h1:Zio80fnEeUKdlSOhTVskMEFSLUQ6TMsMKnXc+Dy2P2A=", "h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=",
"h1:aLLvg36evTyqjtXGV2MjAV8imktXFmry7p/xCu9GQC4=", "h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=",
"h1:azL05eWyy2V8SWkbZZImPWvv8ynG4eqmrbZhjXBDFug=", "h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=",
"h1:ckMysHY4fJmr7o58XMi+DdgOTB/U/Mf1u1JA9ly3g/I=", "h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=",
"h1:jxOwjDNjt5WCb4YjjiMsman91O8Y+MAPz6UwJ4a6F+0=", "h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=",
"h1:u4OfnjSLa4Wk1IUFAzrvMnGgr8MvRHEWVDHEScPK2E8=", "h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=",
"h1:wQkR1oeSkzlHn3rnVuLJRJLBHlg4EHt7Y64DeTjfkjQ=", "h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=",
"zh:0ef99ed39472a94e6a0d6fa733cf0a46bce3bf66eba2873efae8846efdddc237", "zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0",
"zh:2929cbbffcead171d45c88e4a7a59e9c013ea775dafa68b10da8db7cd04b6140", "zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8",
"zh:462601c87118088e1a718842e367af7d8e7620598d426980a6d6b33de759865e", "zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238",
"zh:56766eb62a74a9d88d9efb8486dd3a0c5c9db873d0a980ae9ef1e8af27d74231", "zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f",
"zh:6b4e8810d99498a5a20a5872982a0f1354e79cfc4a7dfe7cc656f1c7eaae47d8", "zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f",
"zh:6d65bdb4ec94b6eecc8abe26d94e2ca09262dc1e7a9934db829f418be0119920", "zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8",
"zh:71adeaf31e41a358ec6095004062e43f56ee7d4b2504e5613ab351d511695641", "zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9",
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:89761c15908ccc2cf9c50bb5cb3be45d3ad0c45fc7c608c6b95f48c0288b7160", "zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6",
"zh:8cc5d7c5939da89cfd01f3e51c84f3576564783acea9db86bd9e32049805ed96", "zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb",
"zh:987cff8225b1dd436cdcb4fc6228689ae7e4281de6896412a2a9a3325c49f05e", "zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b",
"zh:991e83ebb89867d71e01a1c215ed159efb425683b0a44707be8579eb0a337f06", "zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380",
"zh:ab8177ae2d8f5cfa90043a6f867435012cae115f6061b832a7e2462e0ae87a67", "zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7",
"zh:d1ca34df1398f201274a6a18102975148c10ca15aa43cfc56cc9897620929509", "zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
"zh:d34946f70201baf6dda03e3b294c6bbe40d95d0278e97b9f636ded94822b24ac",
] ]
} }
+1 -1
View File
@@ -5,7 +5,7 @@ terraform {
required_providers { required_providers {
cloudflare = { cloudflare = {
source = "cloudflare/cloudflare" source = "cloudflare/cloudflare"
version = "4.50.0" version = "4.52.0"
} }
} }
} }
+15 -6
View File
@@ -1,4 +1,13 @@
# See: #
# WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
#
# Make sure to use the docker-compose.yml of the current release:
#
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
#
# The compose file on main may not be compatible with the latest release.
# For development see:
# - https://immich.app/docs/developer/setup # - https://immich.app/docs/developer/setup
# - https://immich.app/docs/developer/troubleshooting # - https://immich.app/docs/developer/troubleshooting
@@ -16,7 +25,7 @@ services:
context: ../ context: ../
dockerfile: server/Dockerfile dockerfile: server/Dockerfile
target: dev target: dev
restart: always restart: unless-stopped
volumes: volumes:
- ../server:/usr/src/app - ../server:/usr/src/app
- ../open-api:/usr/src/open-api - ../open-api:/usr/src/open-api
@@ -86,12 +95,12 @@ services:
image: immich-machine-learning-dev:latest image: immich-machine-learning-dev:latest
# extends: # extends:
# file: hwaccel.ml.yml # file: hwaccel.ml.yml
# service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference # service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference
build: build:
context: ../machine-learning context: ../machine-learning
dockerfile: Dockerfile dockerfile: Dockerfile
args: args:
- DEVICE=cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - DEVICE=cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference
ports: ports:
- 3003:3003 - 3003:3003
volumes: volumes:
@@ -107,13 +116,13 @@ services:
redis: redis:
container_name: immich_redis container_name: immich_redis
image: redis:6.2-alpine@sha256:905c4ee67b8e0aa955331960d2aa745781e6bd89afc44a8584bfd13bc890f0ae image: docker.io/valkey/valkey:8-bookworm@sha256:42cba146593a5ea9a622002c1b7cba5da7be248650cbb64ecb9c6c33d29794b1
healthcheck: healthcheck:
test: redis-cli ping || exit 1 test: redis-cli ping || exit 1
database: database:
container_name: immich_postgres container_name: immich_postgres
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
env_file: env_file:
- .env - .env
environment: environment:
+18 -19
View File
@@ -1,3 +1,12 @@
#
# WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
#
# Make sure to use the docker-compose.yml of the current release:
#
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
#
# The compose file on main may not be compatible with the latest release.
name: immich-prod name: immich-prod
services: services:
@@ -29,12 +38,12 @@ services:
image: immich-machine-learning:latest image: immich-machine-learning:latest
# extends: # extends:
# file: hwaccel.ml.yml # file: hwaccel.ml.yml
# service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference # service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference
build: build:
context: ../machine-learning context: ../machine-learning
dockerfile: Dockerfile dockerfile: Dockerfile
args: args:
- DEVICE=cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - DEVICE=cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference
ports: ports:
- 3003:3003 - 3003:3003
volumes: volumes:
@@ -47,14 +56,14 @@ services:
redis: redis:
container_name: immich_redis container_name: immich_redis
image: redis:6.2-alpine@sha256:905c4ee67b8e0aa955331960d2aa745781e6bd89afc44a8584bfd13bc890f0ae image: docker.io/valkey/valkey:8-bookworm@sha256:42cba146593a5ea9a622002c1b7cba5da7be248650cbb64ecb9c6c33d29794b1
healthcheck: healthcheck:
test: redis-cli ping || exit 1 test: redis-cli ping || exit 1
restart: always restart: always
database: database:
container_name: immich_postgres container_name: immich_postgres
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
env_file: env_file:
- .env - .env
environment: environment:
@@ -68,22 +77,12 @@ services:
- 5432:5432 - 5432:5432
healthcheck: healthcheck:
test: >- test: >-
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align
--command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')";
echo "checksum failure count is $$Chksum";
[ "$$Chksum" = '0' ] || exit 1
interval: 5m interval: 5m
start_interval: 30s start_interval: 30s
start_period: 5m start_period: 5m
command: >- command: >-
postgres postgres -c shared_preload_libraries=vectors.so -c 'search_path="$$user", public, vectors' -c logging_collector=on -c max_wal_size=2GB -c shared_buffers=512MB -c wal_compression=on
-c shared_preload_libraries=vectors.so
-c 'search_path="$$user", public, vectors'
-c logging_collector=on
-c max_wal_size=2GB
-c shared_buffers=512MB
-c wal_compression=on
restart: always restart: always
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics # set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
@@ -91,7 +90,7 @@ services:
container_name: immich_prometheus container_name: immich_prometheus
ports: ports:
- 9090:9090 - 9090:9090
image: prom/prometheus@sha256:6559acbd5d770b15bb3c954629ce190ac3cbbdb2b7f1c30f0385c4e05104e218 image: prom/prometheus@sha256:502ad90314c7485892ce696cb14a99fceab9fc27af29f4b427f41bd39701a199
volumes: volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml - ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus - prometheus-data:/prometheus
@@ -100,10 +99,10 @@ services:
# add data source for http://immich-prometheus:9090 to get started # add data source for http://immich-prometheus:9090 to get started
immich-grafana: immich-grafana:
container_name: immich_grafana container_name: immich_grafana
command: ['./run.sh', '-disable-reporting'] command: [ './run.sh', '-disable-reporting' ]
ports: ports:
- 3000:3000 - 3000:3000
image: grafana/grafana:11.4.0-ubuntu@sha256:afccec22ba0e4815cca1d2bf3836e414322390dc78d77f1851976ffa8d61051c image: grafana/grafana:11.6.0-ubuntu@sha256:fd8fa48213c624e1a95122f1d93abbf1cf1cbe85fc73212c1e599dbd76c63ff8
volumes: volumes:
- grafana-data:/var/lib/grafana - grafana-data:/var/lib/grafana
+9 -18
View File
@@ -1,10 +1,11 @@
# #
# WARNING: Make sure to use the docker-compose.yml of the current release: # WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
#
# Make sure to use the docker-compose.yml of the current release:
# #
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml # https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
# #
# The compose file on main may not be compatible with the latest release. # The compose file on main may not be compatible with the latest release.
#
name: immich name: immich
@@ -32,12 +33,12 @@ services:
immich-machine-learning: immich-machine-learning:
container_name: immich_machine_learning container_name: immich_machine_learning
# For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag. # For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda # Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release} image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration # extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
# file: hwaccel.ml.yml # file: hwaccel.ml.yml
# service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable # service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes: volumes:
- model-cache:/cache - model-cache:/cache
env_file: env_file:
@@ -48,14 +49,14 @@ services:
redis: redis:
container_name: immich_redis container_name: immich_redis
image: docker.io/redis:6.2-alpine@sha256:905c4ee67b8e0aa955331960d2aa745781e6bd89afc44a8584bfd13bc890f0ae image: docker.io/valkey/valkey:8-bookworm@sha256:42cba146593a5ea9a622002c1b7cba5da7be248650cbb64ecb9c6c33d29794b1
healthcheck: healthcheck:
test: redis-cli ping || exit 1 test: redis-cli ping || exit 1
restart: always restart: always
database: database:
container_name: immich_postgres container_name: immich_postgres
image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
environment: environment:
POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME} POSTGRES_USER: ${DB_USERNAME}
@@ -66,22 +67,12 @@ services:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data - ${DB_DATA_LOCATION}:/var/lib/postgresql/data
healthcheck: healthcheck:
test: >- test: >-
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align
--command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')";
echo "checksum failure count is $$Chksum";
[ "$$Chksum" = '0' ] || exit 1
interval: 5m interval: 5m
start_interval: 30s start_interval: 30s
start_period: 5m start_period: 5m
command: >- command: >-
postgres postgres -c shared_preload_libraries=vectors.so -c 'search_path="$$user", public, vectors' -c logging_collector=on -c max_wal_size=2GB -c shared_buffers=512MB -c wal_compression=on
-c shared_preload_libraries=vectors.so
-c 'search_path="$$user", public, vectors'
-c logging_collector=on
-c max_wal_size=2GB
-c shared_buffers=512MB
-c wal_compression=on
restart: always restart: always
volumes: volumes:
+2 -1
View File
@@ -2,7 +2,8 @@
# The location where your uploaded files are stored # The location where your uploaded files are stored
UPLOAD_LOCATION=./library UPLOAD_LOCATION=./library
# The location where your database files are stored
# The location where your database files are stored. Network shares are not supported for the database
DB_DATA_LOCATION=./postgres DB_DATA_LOCATION=./postgres
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List # To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
+14
View File
@@ -13,6 +13,13 @@ services:
volumes: volumes:
- /lib/firmware/mali_csffw.bin:/lib/firmware/mali_csffw.bin:ro # Mali firmware for your chipset (not always required depending on the driver) - /lib/firmware/mali_csffw.bin:/lib/firmware/mali_csffw.bin:ro # Mali firmware for your chipset (not always required depending on the driver)
- /usr/lib/libmali.so:/usr/lib/libmali.so:ro # Mali driver for your chipset (always required) - /usr/lib/libmali.so:/usr/lib/libmali.so:ro # Mali driver for your chipset (always required)
rknn:
security_opt:
- systempaths=unconfined
- apparmor=unconfined
devices:
- /dev/dri:/dev/dri
cpu: {} cpu: {}
@@ -26,6 +33,13 @@ services:
capabilities: capabilities:
- gpu - gpu
rocm:
group_add:
- video
devices:
- /dev/dri:/dev/dri
- /dev/kfd:/dev/kfd
openvino: openvino:
device_cgroup_rules: device_cgroup_rules:
- 'c 189:* rmw' - 'c 189:* rmw'
+1
View File
@@ -48,6 +48,7 @@ services:
vaapi-wsl: # use this for VAAPI if you're running Immich in WSL2 vaapi-wsl: # use this for VAAPI if you're running Immich in WSL2
devices: devices:
- /dev/dri:/dev/dri - /dev/dri:/dev/dri
- /dev/dxg:/dev/dxg
volumes: volumes:
- /usr/lib/wsl:/usr/lib/wsl - /usr/lib/wsl:/usr/lib/wsl
environment: environment:
+1 -1
View File
@@ -1 +1 @@
22.13.1 22.14.0
+4 -4
View File
@@ -97,7 +97,7 @@ Make sure to [set your reverse proxy](/docs/administration/reverse-proxy/) to al
Also, check the disk space of your reverse proxy. Also, check the disk space of your reverse proxy.
In some cases, proxies cache requests to disk before passing them on, and if disk space runs out, the request fails. In some cases, proxies cache requests to disk before passing them on, and if disk space runs out, the request fails.
If you are using Cloudflare Tunnel, please know that they set a maxiumum filesize of 100 MB that cannot be changed. If you are using Cloudflare Tunnel, please know that they set a maximum filesize of 100 MB that cannot be changed.
At times, files larger than this may work, potentially up to 1 GB. However, the official limit is 100 MB. At times, files larger than this may work, potentially up to 1 GB. However, the official limit is 100 MB.
If you are having issues, we recommend switching to a different network deployment. If you are having issues, we recommend switching to a different network deployment.
@@ -117,7 +117,7 @@ See [Backup and Restore](/docs/administration/backup-and-restore.md).
### Does Immich support reading existing face tag metadata? ### Does Immich support reading existing face tag metadata?
No, it currently does not. There is an [open feature request on GitHub](https://github.com/immich-app/immich/discussions/4348). Yes, it creates new faces and persons from the imported asset metadata. For details see the [feature request #4348](https://github.com/immich-app/immich/discussions/4348) and [PR #6455](https://github.com/immich-app/immich/pull/6455).
### Does Immich support the filtering of NSFW images? ### Does Immich support the filtering of NSFW images?
@@ -170,7 +170,7 @@ If you aren't able to or prefer not to mount Samba on the host (such as Windows
Below is an example in the `docker-compose.yml`. Below is an example in the `docker-compose.yml`.
Change your username, password, local IP, and share name, and see below where the line `- originals:/usr/src/app/originals`, Change your username, password, local IP, and share name, and see below where the line `- originals:/usr/src/app/originals`,
corrolates to the section where the volume `originals` was created. You can call this whatever you like, and map it to the docker container as you like. correlates to the section where the volume `originals` was created. You can call this whatever you like, and map it to the docker container as you like.
For example you could change `originals:` to `Photos:`, and change `- originals:/usr/src/app/originals` to `Photos:/usr/src/app/photos`. For example you could change `originals:` to `Photos:`, and change `- originals:/usr/src/app/originals` to `Photos:/usr/src/app/photos`.
```diff ```diff
@@ -262,7 +262,7 @@ No, this is not supported. Only models listed in the [Hugging Face][huggingface]
### I want to be able to search in other languages besides English. How can I do that? ### I want to be able to search in other languages besides English. How can I do that?
You can change to a multilingual CLIP model. See [here](/docs/features/searching#clip-model) for instructions. You can change to a multilingual CLIP model. See [here](/docs/features/searching#clip-models) for instructions.
### Does Immich support Facial Recognition for videos? ### Does Immich support Facial Recognition for videos?
+10 -5
View File
@@ -30,6 +30,13 @@ As mentioned above, you should make your own backup of these together with the a
You can adjust the schedule and amount of kept backups in the [admin settings](http://my.immich.app/admin/system-settings?isOpen=backup). You can adjust the schedule and amount of kept backups in the [admin settings](http://my.immich.app/admin/system-settings?isOpen=backup).
By default, Immich will keep the last 14 backups and create a new backup every day at 2:00 AM. By default, Immich will keep the last 14 backups and create a new backup every day at 2:00 AM.
#### Trigger Backup
You are able to trigger a backup in the [admin job status page](http://my.immich.app/admin/jobs-status).
Visit the page, open the "Create job" modal from the top right, select "Backup Database" and click "Confirm".
A job will run and trigger a backup, you can verify this worked correctly by checking the logs or the backup folder.
This backup will count towards the last X backups that will be kept based on your settings.
#### Restoring #### Restoring
We hope to make restoring simpler in future versions, for now you can find the backups in the `UPLOAD_LOCATION/backups` folder on your host. We hope to make restoring simpler in future versions, for now you can find the backups in the `UPLOAD_LOCATION/backups` folder on your host.
@@ -53,7 +60,7 @@ docker compose create # Create Docker containers for Immich apps witho
docker start immich_postgres # Start Postgres server docker start immich_postgres # Start Postgres server
sleep 10 # Wait for Postgres server to start up sleep 10 # Wait for Postgres server to start up
# Check the database user if you deviated from the default # Check the database user if you deviated from the default
gunzip < "/path/to/backup/dump.sql.gz" \ gunzip --stdout "/path/to/backup/dump.sql.gz" \
| sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \ | sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
| docker exec -i immich_postgres psql --dbname=postgres --username=<DB_USERNAME> # Restore Backup | docker exec -i immich_postgres psql --dbname=postgres --username=<DB_USERNAME> # Restore Backup
docker compose up -d # Start remainder of Immich apps docker compose up -d # Start remainder of Immich apps
@@ -76,10 +83,8 @@ docker compose create # Create Docker containers for
docker start immich_postgres # Start Postgres server docker start immich_postgres # Start Postgres server
sleep 10 # Wait for Postgres server to start up sleep 10 # Wait for Postgres server to start up
docker exec -it immich_postgres bash # Enter the Docker shell and run the following command docker exec -it immich_postgres bash # Enter the Docker shell and run the following command
# Check the database user if you deviated from the default. If your backup ends in `.gz`, replace `cat` with `gunzip` # Check the database user if you deviated from the default. If your backup ends in `.gz`, replace `cat` with `gunzip --stdout`
cat < "/dump.sql" \ cat "/dump.sql" | sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" | psql --dbname=postgres --username=<DB_USERNAME>
| sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
| psql --dbname=postgres --username=<DB_USERNAME> # Restore Backup
exit # Exit the Docker shell exit # Exit the Docker shell
docker compose up -d # Start remainder of Immich apps docker compose up -d # Start remainder of Immich apps
``` ```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@@ -70,4 +70,4 @@ When installing a new version of pgvecto.rs, you will need to manually update th
If you get the error `driverError: error: permission denied for view pg_vector_index_stat`, you can fix this by connecting to the Immich database and running `GRANT SELECT ON TABLE pg_vector_index_stat TO <immichdbusername>;`. If you get the error `driverError: error: permission denied for view pg_vector_index_stat`, you can fix this by connecting to the Immich database and running `GRANT SELECT ON TABLE pg_vector_index_stat TO <immichdbusername>;`.
[vectors-install]: https://docs.pgvecto.rs/getting-started/installation.html [vectors-install]: https://docs.vectorchord.ai/getting-started/installation.html
@@ -11,6 +11,7 @@ The `immich-server` docker image comes preinstalled with an administrative CLI (
| `enable-oauth-login` | Enable OAuth login | | `enable-oauth-login` | Enable OAuth login |
| `disable-oauth-login` | Disable OAuth login | | `disable-oauth-login` | Disable OAuth login |
| `list-users` | List Immich users | | `list-users` | List Immich users |
| `version` | Print Immich version |
## How to run a command ## How to run a command
@@ -80,3 +81,10 @@ immich-admin list-users
} }
] ]
``` ```
Print Immich Version
```
immich-admin version
v1.129.0
```
@@ -98,6 +98,14 @@ The default Immich log level is `Log` (commonly known as `Info`). The Immich adm
Through this setting, you can manage all the settings related to machine learning in Immich, from the setting of remote machine learning to the model and its parameters Through this setting, you can manage all the settings related to machine learning in Immich, from the setting of remote machine learning to the model and its parameters
You can choose to disable a certain type of machine learning, for example smart search or facial recognition. You can choose to disable a certain type of machine learning, for example smart search or facial recognition.
### URL
The built in (`http://immich-machine-learning:3003`) machine learning server will be configured by default, but you can change this or add additional servers.
Hosting the `immich-machine-learning` container on a machine with a more powerful GPU can be helpful to for processing a large number of photos (such as during batch import) or for faster search.
If more than one URL is provided, each server will be attempted one-at-a-time until one responds successfully, in order from first to last. Servers that don't respond will be temporarily ignored until they come back online.
### Smart Search ### Smart Search
The [smart search](/docs/features/searching) settings allow you to change the [CLIP model](https://openai.com/research/clip). Larger models will typically provide [more accurate search results](https://github.com/immich-app/immich/discussions/11862) but consume more processing power and RAM. When [changing the CLIP model](/docs/FAQ#can-i-use-a-custom-clip-model) it is mandatory to re-run the Smart Search job on all images to fully apply the change. The [smart search](/docs/features/searching) settings allow you to change the [CLIP model](https://openai.com/research/clip). Larger models will typically provide [more accurate search results](https://github.com/immich-app/immich/discussions/11862) but consume more processing power and RAM. When [changing the CLIP model](/docs/FAQ#can-i-use-a-custom-clip-model) it is mandatory to re-run the Smart Search job on all images to fully apply the change.
+1 -1
View File
@@ -31,7 +31,7 @@ Admin can send a welcome email if the Email option is set, you can learn here ho
Admin can specify the storage quota for the user as the instance's admin; once the limit is reached, the user won't be able to upload to the instance anymore. Admin can specify the storage quota for the user as the instance's admin; once the limit is reached, the user won't be able to upload to the instance anymore.
In order to select a storage quota, click on the pencil icon and enter the storage quota in GiB. You can choose an unlimited quota using the value 0 (default). In order to select a storage quota, click on the pencil icon and enter the storage quota in GiB. You can choose an unlimited quota by leaving it empty (default).
:::tip :::tip
The system administrator can see the usage quota percentage of all users in Server Stats page. The system administrator can see the usage quota percentage of all users in Server Stats page.
+8 -9
View File
@@ -50,19 +50,18 @@ The Immich CLI is an [npm](https://www.npmjs.com/) package that lets users contr
The Immich backend is divided into several services, which are run as individual docker containers. The Immich backend is divided into several services, which are run as individual docker containers.
1. `immich-server` - Handle and respond to REST API requests 1. `immich-server` - Handle and respond to REST API requests, execute background jobs (thumbnail generation, metadata extraction, transcoding, etc.)
1. `immich-microservices` - Execute background jobs (thumbnail generation, metadata extraction, transcoding, etc.)
1. `immich-machine-learning` - Execute machine learning models 1. `immich-machine-learning` - Execute machine learning models
1. `postgres` - Persistent data storage 1. `postgres` - Persistent data storage
1. `redis`- Queue management for `immich-microservices` 1. `redis`- Queue management for background jobs
### Immich Server ### Immich Server
The Immich Server is a [TypeScript](https://www.typescriptlang.org/) project written for [Node.js](https://nodejs.org/). It uses the [Nest.js](https://nestjs.com) framework, with [TypeORM](https://typeorm.io/) for database management. The server codebase also loosely follows the [Hexagonal Architecture](<https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)>). Specifically, we aim to separate technology specific implementations (`infra/`) from core business logic (`domain/`). The Immich Server is a [TypeScript](https://www.typescriptlang.org/) project written for [Node.js](https://nodejs.org/). It uses the [Nest.js](https://nestjs.com) framework, [Express](https://expressjs.com/) server, and the query builder [Kysely](https://kysely.dev/). The server codebase also loosely follows the [Hexagonal Architecture](<https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)>). Specifically, we aim to separate technology specific implementations (`src/repositories`) from core business logic (`src/services`).
#### REST Endpoints ### API Endpoints
The server is a list of HTTP endpoints and associated handlers (controllers). Each controller usually implements the following CRUD operations: An incoming HTTP request is mapped to a controller (`src/controllers`). Controllers are collections of HTTP endpoints. Each controller usually implements the following CRUD operations for its respective resource type:
- `POST` `/<type>` - **Create** - `POST` `/<type>` - **Create**
- `GET` `/<type>` - **Read** (all) - `GET` `/<type>` - **Read** (all)
@@ -70,13 +69,13 @@ The server is a list of HTTP endpoints and associated handlers (controllers). Ea
- `PUT` `/<type>/:id` - **Updated** (by id) - `PUT` `/<type>/:id` - **Updated** (by id)
- `DELETE` `/<type>/:id` - **Delete** (by id) - `DELETE` `/<type>/:id` - **Delete** (by id)
#### DTOs ### Domain Transfer Objects (DTOs)
The server uses [Domain Transfer Objects](https://en.wikipedia.org/wiki/Data_transfer_object) as public interfaces for the inputs (query, params, and body) and outputs (response) for each endpoint. DTOs translate to [OpenAPI](./open-api.md) schemas and control the generated code used by each client. The server uses [Domain Transfer Objects](https://en.wikipedia.org/wiki/Data_transfer_object) as public interfaces for the inputs (query, params, and body) and outputs (response) for each endpoint. DTOs translate to [OpenAPI](./open-api.md) schemas and control the generated code used by each client.
### Microservices ### Background Jobs
The Immich Microservices image uses the same `Dockerfile` as the Immich Server, but with a different entrypoint. The Immich Microservices service mainly handles executing jobs, which include the following: Immich uses a [worker](https://github.com/immich-app/immich/blob/main/server/src/utils/misc.ts#L266) to run background jobs. These jobs include:
- Thumbnail Generation - Thumbnail Generation
- Metadata Extraction - Metadata Extraction
+20 -2
View File
@@ -63,6 +63,13 @@ If you only want to do web development connected to an existing, remote backend,
IMMICH_SERVER_URL=https://demo.immich.app/ npm run dev IMMICH_SERVER_URL=https://demo.immich.app/ npm run dev
``` ```
If you're using PowerShell on Windows you may need to set the env var separately like so:
```powershell
$env:IMMICH_SERVER_URL = "https://demo.immich.app/"
npm run dev
```
#### `@immich/ui` #### `@immich/ui`
To see local changes to `@immich/ui` in Immich, do the following: To see local changes to `@immich/ui` in Immich, do the following:
@@ -76,9 +83,20 @@ To see local changes to `@immich/ui` in Immich, do the following:
### Mobile app ### Mobile app
The mobile app `(/mobile)` will required Flutter toolchain 3.13.x to be installed on your system. #### Setup
Please refer to the [Flutter's official documentation](https://flutter.dev/docs/get-started/install) for more information on setting up the toolchain on your machine. 1. Setup Flutter toolchain using FVM.
2. Run `flutter pub get` to install the dependencies.
3. Run `make translation` to generate the translation file.
4. Run `fvm flutter run` to start the app.
#### Translation
To add a new translation text, enter the key-value pair in the `i18n/en.json` in the root of the immich project. Then, from the `mobile/` directory, run
```bash
make translation
```
The mobile app asks you what backend to connect to. You can utilize the demo backend (https://demo.immich.app/) if you don't need to change server code or upload photos. Alternatively, you can run the server yourself per the instructions above. The mobile app asks you what backend to connect to. You can utilize the demo backend (https://demo.immich.app/) if you don't need to change server code or upload photos. Alternatively, you can run the server yourself per the instructions above.
+7 -1
View File
@@ -42,6 +42,12 @@ docker run -it -v "$(pwd)":/import:ro -e IMMICH_INSTANCE_URL=https://your-immich
Please modify the `IMMICH_INSTANCE_URL` and `IMMICH_API_KEY` environment variables as suitable. You can also use a Docker env file to store your sensitive API key. Please modify the `IMMICH_INSTANCE_URL` and `IMMICH_API_KEY` environment variables as suitable. You can also use a Docker env file to store your sensitive API key.
This `docker run` command will directly run the command `immich` inside the container. You can directly append the desired parameters (see under "usage") to the commandline like this:
```bash
docker run -it -v "$(pwd)":/import:ro -e IMMICH_INSTANCE_URL=https://your-immich-instance/api -e IMMICH_API_KEY=your-api-key ghcr.io/immich-app/immich-cli:latest upload -a -c 5 --recursive directory/
```
## Usage ## Usage
<details> <details>
@@ -112,7 +118,7 @@ You begin by authenticating to your Immich server. For instance:
immich login http://192.168.1.216:2283/api HFEJ38DNSDUEG immich login http://192.168.1.216:2283/api HFEJ38DNSDUEG
``` ```
This will store your credentials in a `auth.yml` file in the configuration directory which defaults to `~/.config/`. The directory can be set with the `-d` option or the environment variable `IMMICH_CONFIG_DIR`. Please keep the file secure, either by performing the logout command after you are done, or deleting it manually. This will store your credentials in a `auth.yml` file in the configuration directory which defaults to `~/.config/immich/`. The directory can be set with the `-d` option or the environment variable `IMMICH_CONFIG_DIR`. Please keep the file secure, either by performing the logout command after you are done, or deleting it manually.
Once you are authenticated, you can upload assets to your Immich server. Once you are authenticated, you can upload assets to your Immich server.
+2
View File
@@ -69,6 +69,8 @@ Navigating to Administration > Settings > Machine Learning Settings > Facial Rec
:::tip :::tip
It's better to only tweak the parameters here than to set them to something very different unless you're ready to test a variety of options. If you do need to set a parameter to a strict setting, relaxing other settings can be a good option to compensate, and vice versa. It's better to only tweak the parameters here than to set them to something very different unless you're ready to test a variety of options. If you do need to set a parameter to a strict setting, relaxing other settings can be a good option to compensate, and vice versa.
You can learn how the tune the result in this [Guide](/docs/guides/better-facial-clusters)
::: :::
### Facial recognition model ### Facial recognition model

Before

Width:  |  Height:  |  Size: 4.9 MiB

After

Width:  |  Height:  |  Size: 4.9 MiB

+11 -8
View File
@@ -37,7 +37,7 @@ To validate that Immich can reach your external library, start a shell inside th
### Exclusion Patterns ### Exclusion Patterns
By default, all files in the import paths will be added to the library. If there are files that should not be added, exclusion patterns can be used to exclude them. Exclusion patterns are glob patterns are matched against the full file path. If a file matches an exclusion pattern, it will not be added to the library. Exclusion patterns can be added in the Scan Settings page for each library. Under the hood, Immich uses the [glob](https://www.npmjs.com/package/glob) package to match patterns, so please refer to [their documentation](https://github.com/isaacs/node-glob#glob-primer) to see what patterns are supported. By default, all files in the import paths will be added to the library. If there are files that should not be added, exclusion patterns can be used to exclude them. Exclusion patterns are glob patterns are matched against the full file path. If a file matches an exclusion pattern, it will not be added to the library. Exclusion patterns can be added in the Scan Settings page for each library.
Some basic examples: Some basic examples:
@@ -48,7 +48,11 @@ Some basic examples:
Special characters such as @ should be escaped, for instance: Special characters such as @ should be escaped, for instance:
- `**/\@eadir/**` will exclude all files in any directory named `@eadir` - `**/\@eaDir/**` will exclude all files in any directory named `@eaDir`
:::info
Internally, Immich uses the [glob](https://www.npmjs.com/package/glob) package to process exclusion patterns, and sometimes those patterns are translated into [Postgres LIKE patterns](https://www.postgresql.org/docs/current/functions-matching.html). The intention is to support basic folder exclusions but we recommend against advanced usage since those can't reliably be translated to the Postgres syntax. Please refer to the [glob documentation](https://github.com/isaacs/node-glob#glob-primer) for a basic overview on glob patterns.
:::
### Automatic watching (EXPERIMENTAL) ### Automatic watching (EXPERIMENTAL)
@@ -58,7 +62,7 @@ If your photos are on a network drive, automatic file watching likely won't work
#### Troubleshooting #### Troubleshooting
If you encounter an `ENOSPC` error, you need to increase your file watcher limit. In sysctl, this key is called `fs.inotify.max_user_watched` and has a default value of 8192. Increase this number to a suitable value greater than the number of files you will be watching. Note that Immich has to watch all files in your import paths including any ignored files. If you encounter an `ENOSPC` error, you need to increase your file watcher limit. In sysctl, this key is called `fs.inotify.max_user_watches` and has a default value of 8192. Increase this number to a suitable value greater than the number of files you will be watching. Note that Immich has to watch all files in your import paths including any ignored files.
``` ```
ERROR [LibraryService] Library watcher for library c69faf55-f96d-4aa0-b83b-2d80cbc27d98 encountered error: Error: ENOSPC: System limit for number of file watchers reached, watch '/media/photo.jpg' ERROR [LibraryService] Library watcher for library c69faf55-f96d-4aa0-b83b-2d80cbc27d98 encountered error: Error: ENOSPC: System limit for number of file watchers reached, watch '/media/photo.jpg'
@@ -68,7 +72,7 @@ In rare cases, the library watcher can hang, preventing Immich from starting up.
### Nightly job ### Nightly job
There is an automatic scan job that is scheduled to run once a day. This job also cleans up any libraries stuck in deletion. There is an automatic scan job that is scheduled to run once a day. This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library managment page.
## Usage ## Usage
@@ -91,7 +95,7 @@ The `immich-server` container will need access to the gallery. Modify your docke
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro + - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
+ - /home/user/old-pics:/mnt/media/old-pics:ro + - /home/user/old-pics:/mnt/media/old-pics:ro
+ - /mnt/media/videos:/mnt/media/videos:ro + - /mnt/media/videos:/mnt/media/videos:ro
+ - /mnt/media/videos2:/mnt/media/videos2 # the files in this folder can be deleted, as it does not end with :ro + - /mnt/media/videos2:/mnt/media/videos2 # WARNING: Immich will be able to delete the files in this folder, as it does not end with :ro
+ - "C:/Users/user_name/Desktop/my media:/mnt/media/my-media:ro" # import path in Windows system. + - "C:/Users/user_name/Desktop/my media:/mnt/media/my-media:ro" # import path in Windows system.
``` ```
@@ -111,11 +115,10 @@ These actions must be performed by the Immich administrator.
- Click on Administration -> Libraries - Click on Administration -> Libraries
- Click on Create External Library - Click on Create External Library
- Select which user owns the library, this can not be changed later - Select which user owns the library, this can not be changed later
- Enter `/mnt/media/christmas-trip` then click Add
- Click on Save
- Click the drop-down menu on the newly created library - Click the drop-down menu on the newly created library
- Click on Rename Library and rename it to "Christmas Trip" - Click on Rename Library and rename it to "Christmas Trip"
- Click Edit Import Paths
- Click on Add Path
- Enter `/mnt/media/christmas-trip` then click Add
NOTE: We have to use the `/mnt/media/christmas-trip` path and not the `/mnt/nas/christmas-trip` path since all paths have to be what the Docker containers see. NOTE: We have to use the `/mnt/media/christmas-trip` path and not the `/mnt/nas/christmas-trip` path since all paths have to be what the Docker containers see.
+34 -4
View File
@@ -11,7 +11,9 @@ You do not need to redo any machine learning jobs after enabling hardware accele
- ARM NN (Mali) - ARM NN (Mali)
- CUDA (NVIDIA GPUs with [compute capability](https://developer.nvidia.com/cuda-gpus) 5.2 or higher) - CUDA (NVIDIA GPUs with [compute capability](https://developer.nvidia.com/cuda-gpus) 5.2 or higher)
- OpenVINO (Intel discrete GPUs such as Iris Xe and Arc) - ROCm (AMD GPUs)
- OpenVINO (Intel GPUs such as Iris Xe and Arc)
- RKNN (Rockchip)
## Limitations ## Limitations
@@ -19,6 +21,7 @@ You do not need to redo any machine learning jobs after enabling hardware accele
- Only Linux and Windows (through WSL2) servers are supported. - Only Linux and Windows (through WSL2) servers are supported.
- ARM NN is only supported on devices with Mali GPUs. Other Arm devices are not supported. - ARM NN is only supported on devices with Mali GPUs. Other Arm devices are not supported.
- Some models may not be compatible with certain backends. CUDA is the most reliable. - Some models may not be compatible with certain backends. CUDA is the most reliable.
- Search latency isn't improved by ARM NN due to model compatibility issues preventing its use. However, smart search jobs do make use of ARM NN.
## Prerequisites ## Prerequisites
@@ -33,6 +36,7 @@ You do not need to redo any machine learning jobs after enabling hardware accele
- The `hwaccel.ml.yml` file assumes the path to it is `/usr/lib/libmali.so`, so update accordingly if it is elsewhere - The `hwaccel.ml.yml` file assumes the path to it is `/usr/lib/libmali.so`, so update accordingly if it is elsewhere
- The `hwaccel.ml.yml` file assumes an additional file `/lib/firmware/mali_csffw.bin`, so update accordingly if your device's driver does not require this file - The `hwaccel.ml.yml` file assumes an additional file `/lib/firmware/mali_csffw.bin`, so update accordingly if your device's driver does not require this file
- Optional: Configure your `.env` file, see [environment variables](/docs/install/environment-variables) for ARM NN specific settings - Optional: Configure your `.env` file, see [environment variables](/docs/install/environment-variables) for ARM NN specific settings
- In particular, the `MACHINE_LEARNING_ANN_FP16_TURBO` can significantly improve performance at the cost of very slightly lower accuracy
#### CUDA #### CUDA
@@ -41,21 +45,38 @@ You do not need to redo any machine learning jobs after enabling hardware accele
- The installed driver must be >= 535 (it must support CUDA 12.2). - The installed driver must be >= 535 (it must support CUDA 12.2).
- On Linux (except for WSL2), you also need to have [NVIDIA Container Toolkit][nvct] installed. - On Linux (except for WSL2), you also need to have [NVIDIA Container Toolkit][nvct] installed.
#### ROCm
- The GPU must be supported by ROCm. If it isn't officially supported, you can attempt to use the `HSA_OVERRIDE_GFX_VERSION` environmental variable: `HSA_OVERRIDE_GFX_VERSION=<a supported version, e.g. 10.3.0>`. If this doesn't work, you might need to also set `HSA_USE_SVM=0`.
- The ROCm image is quite large and requires at least 35GiB of free disk space. However, pulling later updates to the service through Docker will generally only amount to a few hundred megabytes as the rest will be cached.
- This backend is new and may experience some issues. For example, GPU power consumption can be higher than usual after running inference, even if the machine learning service is idle. In this case, it will only go back to normal after being idle for 5 minutes (configurable with the [MACHINE_LEARNING_MODEL_TTL](/docs/install/environment-variables) setting).
#### OpenVINO #### OpenVINO
- The server must have a discrete GPU, i.e. Iris Xe or Arc. Expect issues when attempting to use integrated graphics. - Integrated GPUs are more likely to experience issues than discrete GPUs, especially for older processors or servers with low RAM.
- Ensure the server's kernel version is new enough to use the device for hardware accceleration. - Ensure the server's kernel version is new enough to use the device for hardware accceleration.
- Expect higher RAM usage when using OpenVINO compared to CPU processing.
#### RKNN
- You must have a supported Rockchip SoC: only RK3566, RK3568, RK3576 and RK3588 are supported at this moment.
- Make sure you have the appropriate linux kernel driver installed
- This is usually pre-installed on the device vendor's Linux images
- RKNPU driver V0.9.8 or later must be available in the host server
- You may confirm this by running `cat /sys/kernel/debug/rknpu/version` to check the version
- Optional: Configure your `.env` file, see [environment variables](/docs/install/environment-variables) for RKNN specific settings
- In particular, setting `MACHINE_LEARNING_RKNN_THREADS` to 2 or 3 can _dramatically_ improve performance for RK3576 and RK3588 compared to the default of 1, at the expense of multiplying the amount of RAM each model uses by that amount.
## Setup ## Setup
1. If you do not already have it, download the latest [`hwaccel.ml.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`. 1. If you do not already have it, download the latest [`hwaccel.ml.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`.
2. In the `docker-compose.yml` under `immich-machine-learning`, uncomment the `extends` section and change `cpu` to the appropriate backend. 2. In the `docker-compose.yml` under `immich-machine-learning`, uncomment the `extends` section and change `cpu` to the appropriate backend.
3. Still in `immich-machine-learning`, add one of -[armnn, cuda, openvino] to the `image` section's tag at the end of the line. 3. Still in `immich-machine-learning`, add one of -[armnn, cuda, rocm, openvino, rknn] to the `image` section's tag at the end of the line.
4. Redeploy the `immich-machine-learning` container with these updated settings. 4. Redeploy the `immich-machine-learning` container with these updated settings.
### Confirming Device Usage ### Confirming Device Usage
You can confirm the device is being recognized and used by checking its utilization. There are many tools to display this, such as `nvtop` for NVIDIA or Intel and `intel_gpu_top` for Intel. You can confirm the device is being recognized and used by checking its utilization. There are many tools to display this, such as `nvtop` for NVIDIA or Intel, `intel_gpu_top` for Intel, and `radeontop` for AMD.
You can also check the logs of the `immich-machine-learning` container. When a Smart Search or Face Detection job begins, or when you search with text in Immich, you should either see a log for `Available ORT providers` containing the relevant provider (e.g. `CUDAExecutionProvider` in the case of CUDA), or a `Loaded ANN model` log entry without errors in the case of ARM NN. You can also check the logs of the `immich-machine-learning` container. When a Smart Search or Face Detection job begins, or when you search with text in Immich, you should either see a log for `Available ORT providers` containing the relevant provider (e.g. `CUDAExecutionProvider` in the case of CUDA), or a `Loaded ANN model` log entry without errors in the case of ARM NN.
@@ -126,3 +147,12 @@ Note that you should increase job concurrencies to increase overall utilization
- If you encounter an error when a model is running, try a different model to see if the issue is model-specific. - If you encounter an error when a model is running, try a different model to see if the issue is model-specific.
- You may want to increase concurrency past the default for higher utilization. However, keep in mind that this will also increase VRAM consumption. - You may want to increase concurrency past the default for higher utilization. However, keep in mind that this will also increase VRAM consumption.
- Larger models benefit more from hardware acceleration, if you have the VRAM for them. - Larger models benefit more from hardware acceleration, if you have the VRAM for them.
- Compared to ARM NN, RKNPU has:
- Wider model support (including for search, which ARM NN does not accelerate)
- Less heat generation
- Very slightly lower accuracy (RKNPU always uses FP16, while ARM NN by default uses higher precision FP32 unless `MACHINE_LEARNING_ANN_FP16_TURBO` is enabled)
- Varying speed (tested on RK3588):
- If `MACHINE_LEARNING_RKNN_THREADS` is at the default of 1, RKNPU will have substantially lower throughput for ML jobs than ARM NN in most cases, but similar latency (such as when searching)
- If `MACHINE_LEARNING_RKNN_THREADS` is set to 3, it will be somewhat faster than ARM NN at FP32, but somewhat slower than ARM NN if `MACHINE_LEARNING_ANN_FP16_TURBO` is enabled
- When other tasks also use the GPU (like transcoding), RKNPU has a significant advantage over ARM NN as it uses the otherwise idle NPU instead of competing for GPU usage
- Lower RAM usage if `MACHINE_LEARNING_RKNN_THREADS` is at the default of 1, but significantly higher if greater than 1 (which is necessary for it to fully utilize the NPU and hence be comparable in speed to ARM NN)
File diff suppressed because it is too large Load Diff
+17 -16
View File
@@ -8,22 +8,23 @@ For the full list, refer to the [Immich source code](https://github.com/immich-a
## Image formats ## Image formats
| Format | Extension(s) | Supported? | Notes | | Format | Extension(s) | Supported? | Notes |
| :-------- | :---------------------------- | :----------------: | :-------------- | | :---------- | :---------------------------- | :----------------: | :-------------- |
| `AVIF` | `.avif` | :white_check_mark: | | | `AVIF` | `.avif` | :white_check_mark: | |
| `BMP` | `.bmp` | :white_check_mark: | | | `BMP` | `.bmp` | :white_check_mark: | |
| `GIF` | `.gif` | :white_check_mark: | | | `GIF` | `.gif` | :white_check_mark: | |
| `HEIC` | `.heic` | :white_check_mark: | | | `HEIC` | `.heic` | :white_check_mark: | |
| `HEIF` | `.heif` | :white_check_mark: | | | `HEIF` | `.heif` | :white_check_mark: | |
| `JPEG` | `.webp` `.jpg` `.jpe` `.insp` | :white_check_mark: | | | `JPEG 2000` | `.jp2` | :white_check_mark: | |
| `JPEG XL` | `.jxl` | :white_check_mark: | | | `JPEG` | `.webp` `.jpg` `.jpe` `.insp` | :white_check_mark: | |
| `PNG` | `.webp` | :white_check_mark: | | | `JPEG XL` | `.jxl` | :white_check_mark: | |
| `PSD` | `.psd` | :white_check_mark: | Adobe Photoshop | | `PNG` | `.png` | :white_check_mark: | |
| `RAW` | `.raw` | :white_check_mark: | | | `PSD` | `.psd` | :white_check_mark: | Adobe Photoshop |
| `RW2` | `.rw2` | :white_check_mark: | | | `RAW` | `.raw` | :white_check_mark: | |
| `SVG` | `.svg` | :white_check_mark: | | | `RW2` | `.rw2` | :white_check_mark: | |
| `TIFF` | `.tif` `.tiff` | :white_check_mark: | | | `SVG` | `.svg` | :white_check_mark: | |
| `WEBP` | `.webp` | :white_check_mark: | | | `TIFF` | `.tif` `.tiff` | :white_check_mark: | |
| `WEBP` | `.webp` | :white_check_mark: | |
## Video formats ## Video formats
@@ -0,0 +1,72 @@
# Better Facial Recognition Clusters
## Purpose
This guide explains how to optimize facial recognition in systems with large image libraries. By following these steps, you'll achieve better clustering of faces, reducing the need for manual merging.
---
## Important Notes
- **Best Suited For:** Large image libraries after importing a significant number of images.
- **Warning:** This method deletes all previously assigned names.
- **Tip:** **Always take a [backup](/docs/administration/backup-and-restore#database) before proceeding!**
---
## Step-by-Step Instructions
### Objective
To enhance face clustering and ensure the model effectively identifies faces using qualitative initial data.
---
### Steps
#### 1. Adjust Machine Learning Settings
Navigate to:
**Admin → Administration → Settings → Machine Learning Settings**
Make the following changes:
- **Maximum recognition distance (Optional):**
Lower this value, e.g., to **0.4**, if the library contains people with similar facial features.
- **Minimum recognized faces:**
Set this to a **high value** (e.g., 20 For libraries with a large amount of assets (~100K+), and 10 for libraries with medium amount of assets (~40K+)).
> A high value ensures clusters only include faces that appear at least 20/`value` times in the library, improving the initial clustering process.
---
#### 2. Run Reset Jobs
Go to:
**Admin → Administration → Settings → Jobs**
Perform the following:
1. **FACIAL RECOGNITION → Reset**
> These reset jobs rebuild the recognition model based on the new settings.
---
#### 3. Refine Recognition with Lower Thresholds
Once the reset jobs are complete, refine the recognition as follows:
- **Step 1:**
Return to **Minimum recognized faces** in Machine Learning Settings and lower the value to **10** (In medium libraries we will lower the value from 10 to 5).
> Run the job: **FACIAL RECOGNITION → MISSING Mode**
- **Step 2:**
Lower the value again to **3**.
> Run the job: **FACIAL RECOGNITION → MISSING Mode**
:::tip try different values
For certain libraries with a larger or smaller amount of assets, other settings will be better or worse. It is recommended to try different values **before assigning names** and see which settings work best for your library.
:::
---
+4 -3
View File
@@ -6,7 +6,7 @@ This guide explains how to store generated and raw files with docker's volume mo
It is important to remember to update the backup settings after following the guide to back up the new backup paths if using automatic backup tools, especially `profile/`. It is important to remember to update the backup settings after following the guide to back up the new backup paths if using automatic backup tools, especially `profile/`.
::: :::
In our `.env` file, we will define variables that will help us in the future when we want to move to a more advanced server In our `.env` file, we will define the paths we want to use. Note that you don't have to define all of these: UPLOAD_LOCATION will be the base folder that files are stored in by default, with the other paths acting as overrides.
```diff title=".env" ```diff title=".env"
# You can find documentation for all the supported environment variables [here](/docs/install/environment-variables) # You can find documentation for all the supported environment variables [here](/docs/install/environment-variables)
@@ -21,7 +21,7 @@ In our `.env` file, we will define variables that will help us in the future whe
... ...
``` ```
After defining the locations of these files, we will edit the `docker-compose.yml` file accordingly and add the new variables to the `immich-server` container. After defining the locations of these files, we will edit the `docker-compose.yml` file accordingly and add the new variables to the `immich-server` container. These paths are where the mount attaches inside of the container, so don't change those.
```diff title="docker-compose.yml" ```diff title="docker-compose.yml"
services: services:
@@ -35,7 +35,8 @@ services:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
``` ```
Restart Immich to register the changes. After making this change, you have to move the files over to the new folders to make sure Immich can find everything it needs. If you haven't uploaded anything important yet, you can also reset Immich entirely by deleting the database folder.
Then restart Immich to register the changes:
``` ```
docker compose up -d docker compose up -d
+8
View File
@@ -27,6 +27,14 @@ SELECT * FROM "assets" WHERE "originalPath" = 'upload/library/admin/2023/2023-09
SELECT * FROM "assets" WHERE "originalPath" LIKE 'upload/library/admin/2023/%'; SELECT * FROM "assets" WHERE "originalPath" LIKE 'upload/library/admin/2023/%';
``` ```
```sql title="Find by ID"
SELECT * FROM "assets" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9';
```
```sql title="Find by partial ID"
SELECT * FROM "assets" WHERE "id"::text LIKE '%ab431d3a%';
```
:::note :::note
You can calculate the checksum for a particular file by using the command `sha1sum <filename>`. You can calculate the checksum for a particular file by using the command `sha1sum <filename>`.
::: :::
+2 -2
View File
@@ -23,12 +23,12 @@ name: immich_remote_ml
services: services:
immich-machine-learning: immich-machine-learning:
container_name: immich_machine_learning container_name: immich_machine_learning
# For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag. # For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda # Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release} image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # extends:
# file: hwaccel.ml.yml # file: hwaccel.ml.yml
# service: # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable # service: # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes: volumes:
- model-cache:/cache - model-cache:/cache
restart: always restart: always
+4
View File
@@ -1,3 +1,7 @@
---
sidebar_position: 100
---
# Config File # Config File
A config file can be provided as an alternative to the UI configuration. A config file can be provided as an alternative to the UI configuration.
+2 -34
View File
@@ -37,7 +37,7 @@ You can alternatively download these two files from your browser and move them t
</CodeBlock> </CodeBlock>
- Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets. It should be a new directory on the server with enough free space. - Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets. It should be a new directory on the server with enough free space.
- Consider changing `DB_PASSWORD` to a custom value. Postgres is not publically exposed, so this password is only used for local authentication. - Consider changing `DB_PASSWORD` to a custom value. Postgres is not publicly exposed, so this password is only used for local authentication.
To avoid issues with Docker parsing this value, it is best to use only the characters `A-Za-z0-9`. `pwgen` is a handy utility for this. To avoid issues with Docker parsing this value, it is best to use only the characters `A-Za-z0-9`. `pwgen` is a handy utility for this.
- Set your timezone by uncommenting the `TZ=` line. - Set your timezone by uncommenting the `TZ=` line.
- Populate custom database information if necessary. - Populate custom database information if necessary.
@@ -69,39 +69,7 @@ If you get an error `can't set healthcheck.start_interval as feature require Doc
## Next Steps ## Next Steps
Read the [Post Installation](/docs/install/post-install.mdx) steps or setup optional features below. Read the [Post Installation](/docs/install/post-install.mdx) steps and [upgrade instructions](/docs/install/upgrading.md).
### Setting up optional features
- [External Libraries](/docs/features/libraries.md): Adding your existing photo library to Immich
- [Hardware Transcoding](/docs/features/hardware-transcoding.md): Speeding up video transcoding
- [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md): Speeding up various machine learning tasks in Immich
### Upgrading
:::danger Read the release notes
Immich is currently under heavy development, which means you can expect [breaking changes][breaking] and bugs. Therefore, we recommend reading the release notes prior to updating and to take special care when using automated tools like [Watchtower][watchtower].
You can see versions that had breaking changes [here][breaking].
:::
If `IMMICH_VERSION` is set, it will need to be updated to the latest or desired version.
When a new version of Immich is [released][releases], the application can be upgraded and restarted with the following commands, run in the directory with the `docker-compose.yml` file:
```bash title="Upgrade and restart Immich"
docker compose pull && docker compose up -d
```
To clean up disk space, the old version's obsolete container images can be deleted with the following command:
```bash title="Clean up unused Docker images"
docker image prune
```
[compose-file]: https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml [compose-file]: https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
[env-file]: https://github.com/immich-app/immich/releases/latest/download/example.env [env-file]: https://github.com/immich-app/immich/releases/latest/download/example.env
[watchtower]: https://containrrr.dev/watchtower/
[breaking]: https://github.com/immich-app/immich/discussions?discussions_q=label%3Achangelog%3Abreaking-change+sort%3Adate_created
[container-auth]: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#authenticating-to-the-container-registry
[releases]: https://github.com/immich-app/immich/releases
+31 -23
View File
@@ -11,7 +11,7 @@ Just restarting the containers does not replace the environment within the conta
In order to recreate the container using docker compose, run `docker compose up -d`. In order to recreate the container using docker compose, run `docker compose up -d`.
In most cases docker will recognize that the `.env` file has changed and recreate the affected containers. In most cases docker will recognize that the `.env` file has changed and recreate the affected containers.
If this should not work, try running `docker compose up -d --force-recreate`. If this does not work, try running `docker compose up -d --force-recreate`.
::: :::
@@ -20,8 +20,8 @@ If this should not work, try running `docker compose up -d --force-recreate`.
| Variable | Description | Default | Containers | | Variable | Description | Default | Containers |
| :----------------- | :------------------------------ | :-------: | :----------------------- | | :----------------- | :------------------------------ | :-------: | :----------------------- |
| `IMMICH_VERSION` | Image tags | `release` | server, machine learning | | `IMMICH_VERSION` | Image tags | `release` | server, machine learning |
| `UPLOAD_LOCATION` | Host Path for uploads | | server | | `UPLOAD_LOCATION` | Host path for uploads | | server |
| `DB_DATA_LOCATION` | Host Path for Postgres database | | database | | `DB_DATA_LOCATION` | Host path for Postgres database | | database |
:::tip :::tip
These environment variables are used by the `docker-compose.yml` file and do **NOT** affect the containers directly. These environment variables are used by the `docker-compose.yml` file and do **NOT** affect the containers directly.
@@ -33,15 +33,15 @@ These environment variables are used by the `docker-compose.yml` file and do **N
| :---------------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- | | :---------------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- |
| `TZ` | Timezone | <sup>\*1</sup> | server | microservices | | `TZ` | Timezone | <sup>\*1</sup> | server | microservices |
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices | | `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
| `IMMICH_LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices | | `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
| `IMMICH_MEDIA_LOCATION` | Media Location inside the container ⚠️**You probably shouldn't set this**<sup>\*2</sup>⚠️ | `./upload`<sup>\*3</sup> | server | api, microservices | | `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**<sup>\*2</sup>⚠️ | `./upload`<sup>\*3</sup> | server | api, microservices |
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices | | `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | | | `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
| `CPU_CORES` | Amount of cores available to the immich server | auto-detected cpu core count | server | | | `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api | | `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices | | `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices |
| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices | | `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices |
| `IMMICH_TRUSTED_PROXIES` | List of comma separated IPs set as trusted proxies | | server | api | | `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api |
| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices | | `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices |
\*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`. \*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`.
@@ -50,7 +50,7 @@ These environment variables are used by the `docker-compose.yml` file and do **N
\*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead. \*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead.
\*3: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`. \*3: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`.
It only need to be set if the Immich deployment method is changing. It only needs to be set if the Immich deployment method is changing.
## Workers ## Workers
@@ -75,12 +75,12 @@ Information on the current workers can be found [here](/docs/administration/jobs
| Variable | Description | Default | Containers | | Variable | Description | Default | Containers |
| :---------------------------------- | :----------------------------------------------------------------------- | :----------: | :----------------------------- | | :---------------------------------- | :----------------------------------------------------------------------- | :----------: | :----------------------------- |
| `DB_URL` | Database URL | | server | | `DB_URL` | Database URL | | server |
| `DB_HOSTNAME` | Database Host | `database` | server | | `DB_HOSTNAME` | Database host | `database` | server |
| `DB_PORT` | Database Port | `5432` | server | | `DB_PORT` | Database port | `5432` | server |
| `DB_USERNAME` | Database User | `postgres` | server, database<sup>\*1</sup> | | `DB_USERNAME` | Database user | `postgres` | server, database<sup>\*1</sup> |
| `DB_PASSWORD` | Database Password | `postgres` | server, database<sup>\*1</sup> | | `DB_PASSWORD` | Database password | `postgres` | server, database<sup>\*1</sup> |
| `DB_DATABASE_NAME` | Database Name | `immich` | server, database<sup>\*1</sup> | | `DB_DATABASE_NAME` | Database name | `immich` | server, database<sup>\*1</sup> |
| `DB_VECTOR_EXTENSION`<sup>\*2</sup> | Database Vector Extension (one of [`pgvector`, `pgvecto.rs`]) | `pgvecto.rs` | server | | `DB_VECTOR_EXTENSION`<sup>\*2</sup> | Database vector extension (one of [`pgvector`, `pgvecto.rs`]) | `pgvecto.rs` | server |
| `DB_SKIP_MIGRATIONS` | Whether to skip running migrations on startup (one of [`true`, `false`]) | `false` | server | | `DB_SKIP_MIGRATIONS` | Whether to skip running migrations on startup (one of [`true`, `false`]) | `false` | server |
\*1: The values of `DB_USERNAME`, `DB_PASSWORD`, and `DB_DATABASE_NAME` are passed to the Postgres container as the variables `POSTGRES_USER`, `POSTGRES_PASSWORD`, and `POSTGRES_DB` in `docker-compose.yml`. \*1: The values of `DB_USERNAME`, `DB_PASSWORD`, and `DB_DATABASE_NAME` are passed to the Postgres container as the variables `POSTGRES_USER`, `POSTGRES_PASSWORD`, and `POSTGRES_DB` in `docker-compose.yml`.
@@ -103,18 +103,18 @@ When `DB_URL` is defined, the `DB_HOSTNAME`, `DB_PORT`, `DB_USERNAME`, `DB_PASSW
| Variable | Description | Default | Containers | | Variable | Description | Default | Containers |
| :--------------- | :------------- | :-----: | :--------- | | :--------------- | :------------- | :-----: | :--------- |
| `REDIS_URL` | Redis URL | | server | | `REDIS_URL` | Redis URL | | server |
| `REDIS_SOCKET` | Redis Socket | | server | | `REDIS_SOCKET` | Redis socket | | server |
| `REDIS_HOSTNAME` | Redis Host | `redis` | server | | `REDIS_HOSTNAME` | Redis host | `redis` | server |
| `REDIS_PORT` | Redis Port | `6379` | server | | `REDIS_PORT` | Redis port | `6379` | server |
| `REDIS_USERNAME` | Redis Username | | server | | `REDIS_USERNAME` | Redis username | | server |
| `REDIS_PASSWORD` | Redis Password | | server | | `REDIS_PASSWORD` | Redis password | | server |
| `REDIS_DBINDEX` | Redis DB Index | `0` | server | | `REDIS_DBINDEX` | Redis DB index | `0` | server |
:::info :::info
All `REDIS_` variables must be provided to all Immich workers, including `api` and `microservices`. All `REDIS_` variables must be provided to all Immich workers, including `api` and `microservices`.
`REDIS_URL` must start with `ioredis://` and then include a `base64` encoded JSON string for the configuration. `REDIS_URL` must start with `ioredis://` and then include a `base64` encoded JSON string for the configuration.
More info can be found in the upstream [ioredis] documentation. More information can be found in the upstream [ioredis] documentation.
When `REDIS_URL` or `REDIS_SOCKET` are defined, the `REDIS_HOSTNAME`, `REDIS_PORT`, `REDIS_USERNAME`, `REDIS_PASSWORD`, and `REDIS_DBINDEX` variables are ignored. When `REDIS_URL` or `REDIS_SOCKET` are defined, the `REDIS_HOSTNAME`, `REDIS_PORT`, `REDIS_USERNAME`, `REDIS_PASSWORD`, and `REDIS_DBINDEX` variables are ignored.
::: :::
@@ -168,6 +168,10 @@ Redis (Sentinel) URL example JSON before encoding:
| `MACHINE_LEARNING_ANN_TUNING_LEVEL` | ARM-NN GPU tuning level (1: rapid, 2: normal, 3: exhaustive) | `2` | machine learning | | `MACHINE_LEARNING_ANN_TUNING_LEVEL` | ARM-NN GPU tuning level (1: rapid, 2: normal, 3: exhaustive) | `2` | machine learning |
| `MACHINE_LEARNING_DEVICE_IDS`<sup>\*4</sup> | Device IDs to use in multi-GPU environments | `0` | machine learning | | `MACHINE_LEARNING_DEVICE_IDS`<sup>\*4</sup> | Device IDs to use in multi-GPU environments | `0` | machine learning |
| `MACHINE_LEARNING_MAX_BATCH_SIZE__FACIAL_RECOGNITION` | Set the maximum number of faces that will be processed at once by the facial recognition model | None (`1` if using OpenVINO) | machine learning | | `MACHINE_LEARNING_MAX_BATCH_SIZE__FACIAL_RECOGNITION` | Set the maximum number of faces that will be processed at once by the facial recognition model | None (`1` if using OpenVINO) | machine learning |
| `MACHINE_LEARNING_PING_TIMEOUT` | How long (ms) to wait for a PING response when checking if an ML server is available | `2000` | server |
| `MACHINE_LEARNING_AVAILABILITY_BACKOFF_TIME` | How long to ignore ML servers that are offline before trying again | `30000` | server |
| `MACHINE_LEARNING_RKNN` | Enable RKNN hardware acceleration if supported | `True` | machine learning |
| `MACHINE_LEARNING_RKNN_THREADS` | How many threads of RKNN runtime should be spinned up while inferencing. | `1` | machine learning |
\*1: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones. \*1: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones.
@@ -179,7 +183,11 @@ Redis (Sentinel) URL example JSON before encoding:
:::info :::info
Other machine learning parameters can be tuned from the admin UI. While the `textual` model is the only one required for smart search, some users may experience slow first searches
due to backups triggering loading of the other models into memory, which blocks other requests until completed.
To avoid this, you can preload the other models (`visual`, `recognition`, and `detection`) if you have enough RAM to do so.
Additional machine learning parameters can be tuned from the admin UI.
::: :::
@@ -210,7 +218,7 @@ the `_FILE` variable should be set to the path of a file containing the variable
details on how to use Docker Secrets in the Postgres image. details on how to use Docker Secrets in the Postgres image.
\*2: See [this comment][docker-secrets-example] for an example of how \*2: See [this comment][docker-secrets-example] for an example of how
to use use a Docker secret for the password in the Redis container. to use a Docker secret for the password in the Redis container.
[tz-list]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List [tz-list]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
[docker-secrets-example]: https://github.com/docker-library/redis/issues/46#issuecomment-335326234 [docker-secrets-example]: https://github.com/docker-library/redis/issues/46#issuecomment-335326234
+6
View File
@@ -41,3 +41,9 @@ A list of common steps to take after installing Immich include:
## Step 7 - Setup Server Backups ## Step 7 - Setup Server Backups
<ServerBackup /> <ServerBackup />
## Setting up optional features
- [External Libraries](/docs/features/libraries.md): Adding your existing photo library to Immich
- [Hardware Transcoding](/docs/features/hardware-transcoding.md): Speeding up video transcoding
- [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md): Speeding up various machine learning tasks in Immich
+70
View File
@@ -0,0 +1,70 @@
---
sidebar_position: 85
---
# Synology [Community]
:::note
This is a community contribution and not officially supported by the Immich team, but included here for convenience.
Community support can be found in the dedicated channel on the [Discord Server](https://discord.immich.app/).
**Please report app issues to the corresponding [Github Repository](https://github.com/truenas/charts/tree/master/community/immich).**
:::
Immich can easily be installed on a Synology NAS using Container Manager within DSM. If you have not installed Container Manager already, you can install it in the Packages Center. Refer to the [Container Manager docs](https://kb.synology.com/en-us/DSM/help/ContainerManager/docker_desc?version=7) for more information on using Container Manager.
## Step 1 - Download the required files
Create a directory of your choice (e.g. `./immich-app`) to house Immich. In general, it's a best practice to have all Docker-based applications running under the `./docker` directory, so in this case, your directory structure will look like `./docker/immich-app`.
Now create a `./postgres` and `./library` directory as sub-directories of the `./docker/immich-app`.
When you're all done, you should have the following:
- `./docker/immich-app/postgres`
- `./docker/immich-app/library`
Download [`docker-compose.yml`](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml) and [`example.env`](https://github.com/immich-app/immich/releases/latest/download/example.env) to your computer. Upload the files to the `./docker/immich-app` directory.
## Step 2 - Populate the .env file with custom values
Follow [Step 2 in Docker Compose](./docker-compose#step-2---populate-the-env-file-with-custom-values) for instructions on customizing the `.env` file, and then return back to this guide to continue.
## Step 3 - Create a new project in Container Manager
Open Container Manager, and select the "**Project**" action on the left navigation bar and then click "**Create**".
![Create Project](../../static/img/synology-container-manager-create-project.png)
In the settings of your new project, set "**Project name**" to a name you'll remember, such as _immich-app_. When setting the "**Path**", select the `./docker/immich-app` directory you created earlier. Doing so will prompt a message to use the existing `docker-compose.yml` already present in the directory for your project. Click "**OK**" to continue.
![Set Path](../../static/img/synology-container-manager-set-path.png)
The following screen will give you the option to further customize your `docker-compose.yml` file, giving you a warning regarding the `start_interval` property. Under the `healthcheck` heading, remove the `start_interval: 30s` completely and click "**Next**".
![start interval](../../static/img/synology-container-manager-customize-docker-compose.png)
Skip the section asking to set-up a portal for Web Station, and then complete the wizard which will build and start the containers for your project.
Once your containers are successfully running, navigate to the "**Container**" section of Container Manager, right-click on the "**immich-server**" container, and choose the "**Details**".
Scroll to the bottom of the "**Details**" section, and find the `IP Address` of the container, located in the `Network` section. Take note of the container's IP address as you will need it for **Step 4**.
![Container Details](../../static/img/synology-container-manager-container-details.png)
## Step 4 - Configure Firewall Settings
Once your project completes the build process, your containers will start. In order to be able to access Immich from your browser, you need to configure the firewall settings for your Synology NAS.
Open "**Control Panel**" on your Synology NAS, and select "**Security**". Navigate to "**Firewall**"
![Firewall rules](../../static/img/synology-firewall-rules.png)
Click "**Edit Rules**" and add the following firewall rules:
- Add a "**Source IP**" rule for the IP address of your container that you obtained in Step 3 above
- Add a "**Ports**" rule for the port specified in the `docker-compose.yml`, which should be `2283`
## Next Steps
Read the [Post Installation](/docs/install/post-install.mdx) steps and [upgrade instructions](/docs/install/upgrading.md).
+11 -3
View File
@@ -41,7 +41,7 @@ className="border rounded-xl"
:::info Permissions :::info Permissions
The **pgData** dataset must be owned by the user `netdata` (UID 999) for postgres to start. The other datasets must be owned by the user `root` (UID 0) or a group that includes the user `root` (UID 0) for immich to have the necessary permissions. The **pgData** dataset must be owned by the user `netdata` (UID 999) for postgres to start. The other datasets must be owned by the user `root` (UID 0) or a group that includes the user `root` (UID 0) for immich to have the necessary permissions.
If the **library** dataset uses ACL it must have [ACL mode](https://www.truenas.com/docs/core/coretutorials/storage/pools/permissions/#access-control-lists) set to `Passthrough` if you plan on using a [storage template](/docs/administration/storage-template.mdx) and the dataset is configured for network sharing (its ACL type is set to `SMB/NFSv4`). When the template is applied and files need to be moved from **upload** to **library**, immich performs `chmod` internally and needs to be allowed to execute the command. [More info.](https://github.com/immich-app/immich/pull/13017) If the **library** dataset uses ACL it must have [ACL mode](https://www.truenas.com/docs/core/coretutorials/storage/pools/permissions/#access-control-lists) set to `Passthrough` if you plan on using a [storage template](/docs/administration/storage-template.mdx) and the dataset is configured for network sharing (its ACL type is set to `SMB/NFSv4`). When the template is applied and files need to be moved from **upload** to **library**, Immich performs `chmod` internally and needs to be allowed to execute the command. [More info.](https://github.com/immich-app/immich/pull/13017)
::: :::
## Installing the Immich Application ## Installing the Immich Application
@@ -160,6 +160,10 @@ The image above has example values.
### Additional Storage [(External Libraries)](/docs/features/libraries) ### Additional Storage [(External Libraries)](/docs/features/libraries)
:::danger Advanced Users Only
This feature should only be used by advanced users. If this is your first time installing Immich, then DO NOT mount an external library until you have a working setup. Also, your mount path MUST be something unique and should NOT be your library or upload location or a Linux directory like `/lib`. The picture below shows a valid example.
:::
<img <img
src={require('./img/truenas10.webp').default} src={require('./img/truenas10.webp').default}
width="40%" width="40%"
@@ -168,7 +172,7 @@ className="border rounded-xl"
/> />
You may configure [External Libraries](/docs/features/libraries) by mounting them using **Additional Storage**. You may configure [External Libraries](/docs/features/libraries) by mounting them using **Additional Storage**.
The **Mount Path** is the loaction you will need to copy and paste into the External Library settings within Immich. The **Mount Path** is the location you will need to copy and paste into the External Library settings within Immich.
The **Host Path** is the location on the TrueNAS SCALE server where your external library is located. The **Host Path** is the location on the TrueNAS SCALE server where your external library is located.
<!-- A section for Labels would go here but I don't know what they do. --> <!-- A section for Labels would go here but I don't know what they do. -->
@@ -194,7 +198,7 @@ The **CPU** value was specified in a different format with a default of `4000m`
The **Memory** value was specified in a different format with a default of `8Gi` which is 8 GiB of RAM. The value was specified in bytes or a number with a measurement suffix. Examples: `129M`, `123Mi`, `1000000000` The **Memory** value was specified in a different format with a default of `8Gi` which is 8 GiB of RAM. The value was specified in bytes or a number with a measurement suffix. Examples: `129M`, `123Mi`, `1000000000`
::: :::
Enable **GPU Configuration** options if you have a GPU that you will use for [Hardware Transcoding](/docs/features/hardware-transcoding) and/or [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md). More info: [GPU Passtrough Docs for TrueNAS Apps](https://www.truenas.com/docs/truenasapps/#gpu-passthrough) Enable **GPU Configuration** options if you have a GPU that you will use for [Hardware Transcoding](/docs/features/hardware-transcoding) and/or [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md). More info: [GPU Passthrough Docs for TrueNAS Apps](https://www.truenas.com/docs/truenasapps/#gpu-passthrough)
### Install ### Install
@@ -243,6 +247,10 @@ Some examples are: `IMMICH_VERSION`, `UPLOAD_LOCATION`, `DB_DATA_LOCATION`, `TZ`
## Updating the App ## Updating the App
:::danger
Make sure to read the general [upgrade instructions](/docs/install/upgrading.md).
:::
When updates become available, SCALE alerts and provides easy updates. When updates become available, SCALE alerts and provides easy updates.
To update the app to the latest version: To update the app to the latest version:
+6 -2
View File
@@ -72,12 +72,12 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
</ul> </ul>
</details> </details>
5. Click "**Save Changes**", you will be promoted to edit stack UI labels, just leave this blank and click "**Ok**" 5. Click "**Save Changes**", you will be prompted to edit stack UI labels, just leave this blank and click "**Ok**"
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**" 6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following: 7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following:
- `UPLOAD_LOCATION`: Create a folder in your Images Unraid share and place the **absolute** location here > For example my _"images"_ share has a folder within it called _"immich"_. If I browse to this directory in the terminal and type `pwd` the output is `/mnt/user/images/immich`. This is the exact value I need to enter as my `UPLOAD_LOCATION` - `UPLOAD_LOCATION`: Create a folder in your Images Unraid share and place the **absolute** location here > For example my _"images"_ share has a folder within it called _"immich"_. If I browse to this directory in the terminal and type `pwd` the output is `/mnt/user/images/immich`. This is the exact value I need to enter as my `UPLOAD_LOCATION`
- `DB_DATA_LOCATION`: Change this to use an Unraid share (preferably a cache pool, e.g. `/mnt/user/appdata`). If left at default it will try to use Unraid's `/boot/config/plugins/compose.manager/projects/[stack_name]/postgres` folder which it doesn't have permissions to, resulting in this container continuously restarting. - `DB_DATA_LOCATION`: Change this to use an Unraid share (preferably a cache pool, e.g. `/mnt/user/appdata/postgresql/data`). This uses the `appdata` share. Do also create the `postgresql` folder, by running `mkdir /mnt/user/{share_location}/postgresql/data`. If left at default it will try to use Unraid's `/boot/config/plugins/compose.manager/projects/[stack_name]/postgres` folder which it doesn't have permissions to, resulting in this container continuously restarting.
<img <img
src={require('./img/unraid05.webp').default} src={require('./img/unraid05.webp').default}
@@ -131,6 +131,10 @@ For more information on how to use the application once installed, please refer
## Updating Steps ## Updating Steps
:::danger
Make sure to read the general [upgrade instructions](/docs/install/upgrading.md).
:::
Updating is extremely easy however it's important to be aware that containers managed via the Docker Compose Manager plugin do not integrate with Unraid's native dockerman UI, the label "_update ready_" will always be present on containers installed via the Docker Compose Manager. Updating is extremely easy however it's important to be aware that containers managed via the Docker Compose Manager plugin do not integrate with Unraid's native dockerman UI, the label "_update ready_" will always be present on containers installed via the Docker Compose Manager.
<img <img
+29
View File
@@ -0,0 +1,29 @@
---
sidebar_position: 95
---
# Upgrading
:::danger Read the release notes
Immich is currently under heavy development, which means you can expect [breaking changes][breaking] and bugs. You should read the release notes prior to updating and take special care when using automated tools like [Watchtower][watchtower].
You can see versions that had breaking changes [here][breaking].
:::
When a new version of Immich is [released][releases], you should read the release notes and account for any breaking changes noted (as mentioned above).
If you use `IMMICH_VERSION` in your `.env` file, it will need to be updated to the latest or desired version.
After that, the application can be upgraded and restarted with the following commands, run in the directory with the `docker-compose.yml` file:
```bash title="Upgrade and restart Immich"
docker compose pull && docker compose up -d
```
To clean up disk space, the old version's obsolete container images can be deleted with the following command:
```bash title="Clean up unused Docker images"
docker image prune
```
[watchtower]: https://containrrr.dev/watchtower/
[breaking]: https://github.com/immich-app/immich/discussions?discussions_q=label%3Achangelog%3Abreaking-change+sort%3Adate_created
[releases]: https://github.com/immich-app/immich/releases
+5
View File
@@ -1,2 +1,7 @@
Now that you have imported some pictures, you should setup server backups to preserve your memories. Now that you have imported some pictures, you should setup server backups to preserve your memories.
You can do so by following our [backup guide](/docs/administration/backup-and-restore.md). You can do so by following our [backup guide](/docs/administration/backup-and-restore.md).
:::danger
Immich is still under heavy development _and_ handles very important data.
It is essential that you set up good backups, and test them.
:::
+2 -2
View File
@@ -110,9 +110,9 @@ const config = {
label: 'API', label: 'API',
}, },
{ {
to: '/blog', href: 'https://immich.store',
position: 'right', position: 'right',
label: 'Blog', label: 'Merch',
}, },
{ {
href: 'https://github.com/immich-app/immich', href: 'https://github.com/immich-app/immich',
+3371 -1986
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -36,6 +36,8 @@
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/module-type-aliases": "~3.7.0", "@docusaurus/module-type-aliases": "~3.7.0",
"@docusaurus/tsconfig": "^3.7.0",
"@docusaurus/types": "^3.7.0",
"prettier": "^3.2.4", "prettier": "^3.2.4",
"typescript": "^5.1.6" "typescript": "^5.1.6"
}, },
@@ -55,6 +57,6 @@
"node": ">=20" "node": ">=20"
}, },
"volta": { "volta": {
"node": "22.13.1" "node": "22.14.0"
} }
} }
+5
View File
@@ -53,6 +53,11 @@ const guides: CommunityGuidesProps[] = [
description: 'How to configure an existing fail2ban installation to block incorrect login attempts.', description: 'How to configure an existing fail2ban installation to block incorrect login attempts.',
url: 'https://github.com/immich-app/immich/discussions/3243#discussioncomment-6681948', url: 'https://github.com/immich-app/immich/discussions/3243#discussioncomment-6681948',
}, },
{
title: 'Immich remote access with NordVPN Meshnet',
description: 'Access Immich with an end-to-end encrypted connection.',
url: 'https://meshnet.nordvpn.com/how-to/remote-files-media-access/immich-remote-access',
},
]; ];
function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element { function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element {
+2 -1
View File
@@ -1,2 +1,3 @@
export const discordPath = export const discordPath =
'M 9.1367188 3.8691406 C 9.1217187 3.8691406 9.1067969 3.8700938 9.0917969 3.8710938 C 8.9647969 3.8810937 5.9534375 4.1403594 4.0234375 5.6933594 C 3.0154375 6.6253594 1 12.073203 1 16.783203 C 1 16.866203 1.0215 16.946531 1.0625 17.019531 C 2.4535 19.462531 6.2473281 20.102859 7.1113281 20.130859 L 7.1269531 20.130859 C 7.2799531 20.130859 7.4236719 20.057594 7.5136719 19.933594 L 8.3886719 18.732422 C 6.0296719 18.122422 4.8248594 17.086391 4.7558594 17.025391 C 4.5578594 16.850391 4.5378906 16.549563 4.7128906 16.351562 C 4.8068906 16.244563 4.9383125 16.189453 5.0703125 16.189453 C 5.1823125 16.189453 5.2957188 16.228594 5.3867188 16.308594 C 5.4157187 16.334594 7.6340469 18.216797 11.998047 18.216797 C 16.370047 18.216797 18.589328 16.325641 18.611328 16.306641 C 18.702328 16.227641 18.815734 16.189453 18.927734 16.189453 C 19.059734 16.189453 19.190156 16.243562 19.285156 16.351562 C 19.459156 16.549563 19.441141 16.851391 19.244141 17.025391 C 19.174141 17.087391 17.968375 18.120469 15.609375 18.730469 L 16.484375 19.933594 C 16.574375 20.057594 16.718094 20.130859 16.871094 20.130859 L 16.886719 20.130859 C 17.751719 20.103859 21.5465 19.463531 22.9375 17.019531 C 22.9785 16.947531 23 16.866203 23 16.783203 C 23 12.073203 20.984172 6.624875 19.951172 5.671875 C 18.047172 4.140875 15.036203 3.8820937 14.908203 3.8710938 C 14.895203 3.8700938 14.880188 3.8691406 14.867188 3.8691406 C 14.681188 3.8691406 14.510594 3.9793906 14.433594 4.1503906 C 14.427594 4.1623906 14.362062 4.3138281 14.289062 4.5488281 C 15.548063 4.7608281 17.094141 5.1895937 18.494141 6.0585938 C 18.718141 6.1975938 18.787437 6.4917969 18.648438 6.7167969 C 18.558438 6.8627969 18.402188 6.9433594 18.242188 6.9433594 C 18.156188 6.9433594 18.069234 6.9200937 17.990234 6.8710938 C 15.584234 5.3800938 12.578 5.3046875 12 5.3046875 C 11.422 5.3046875 8.4157187 5.3810469 6.0117188 6.8730469 C 5.9327188 6.9210469 5.8457656 6.9433594 5.7597656 6.9433594 C 5.5997656 6.9433594 5.4425625 6.86475 5.3515625 6.71875 C 5.2115625 6.49375 5.2818594 6.1985938 5.5058594 6.0585938 C 6.9058594 5.1905937 8.4528906 4.7627812 9.7128906 4.5507812 C 9.6388906 4.3147813 9.5714062 4.1643437 9.5664062 4.1523438 C 9.4894063 3.9813438 9.3217188 3.8691406 9.1367188 3.8691406 z M 12 7.3046875 C 12.296 7.3046875 14.950594 7.3403125 16.933594 8.5703125 C 17.326594 8.8143125 17.777234 8.9453125 18.240234 8.9453125 C 18.633234 8.9453125 19.010656 8.8555 19.347656 8.6875 C 19.964656 10.2405 20.690828 12.686219 20.923828 15.199219 C 20.883828 15.143219 20.840922 15.089109 20.794922 15.037109 C 20.324922 14.498109 19.644687 14.191406 18.929688 14.191406 C 18.332687 14.191406 17.754078 14.405437 17.330078 14.773438 C 17.257078 14.832437 15.505 16.21875 12 16.21875 C 8.496 16.21875 6.7450313 14.834687 6.7070312 14.804688 C 6.2540312 14.407687 5.6742656 14.189453 5.0722656 14.189453 C 4.3612656 14.189453 3.6838438 14.494391 3.2148438 15.025391 C 3.1658438 15.080391 3.1201719 15.138266 3.0761719 15.197266 C 3.3091719 12.686266 4.0344375 10.235594 4.6484375 8.6835938 C 4.9864375 8.8525938 5.3657656 8.9433594 5.7597656 8.9433594 C 6.2217656 8.9433594 6.6724531 8.8143125 7.0644531 8.5703125 C 9.0494531 7.3393125 11.704 7.3046875 12 7.3046875 z M 8.890625 10.044922 C 7.966625 10.044922 7.2167969 10.901031 7.2167969 11.957031 C 7.2167969 13.013031 7.965625 13.869141 8.890625 13.869141 C 9.815625 13.869141 10.564453 13.013031 10.564453 11.957031 C 10.564453 10.900031 9.815625 10.044922 8.890625 10.044922 z M 15.109375 10.044922 C 14.185375 10.044922 13.435547 10.901031 13.435547 11.957031 C 13.435547 13.013031 14.184375 13.869141 15.109375 13.869141 C 16.034375 13.869141 16.783203 13.013031 16.783203 11.957031 C 16.783203 10.900031 16.033375 10.044922 15.109375 10.044922 z'; 'M81.15,0c-1.2376,2.1973-2.3489,4.4704-3.3591,6.794-9.5975-1.4396-19.3718-1.4396-28.9945,0-.985-2.3236-2.1216-4.5967-3.3591-6.794-9.0166,1.5407-17.8059,4.2431-26.1405,8.0568C2.779,32.5304-1.6914,56.3725.5312,79.8863c9.6732,7.1476,20.5083,12.603,32.0505,16.0884,2.6014-3.4854,4.8998-7.1981,6.8698-11.0623-3.738-1.3891-7.3497-3.1318-10.8098-5.1523.9092-.6567,1.7932-1.3386,2.6519-1.9953,20.281,9.547,43.7696,9.547,64.0758,0,.8587.7072,1.7427,1.3891,2.6519,1.9953-3.4601,2.0457-7.0718,3.7632-10.835,5.1776,1.97,3.8642,4.2683,7.5769,6.8698,11.0623,11.5419-3.4854,22.3769-8.9156,32.0509-16.0631,2.626-27.2771-4.496-50.9172-18.817-71.8548C98.9811,4.2684,90.1918,1.5659,81.1752.0505l-.0252-.0505ZM42.2802,65.4144c-6.2383,0-11.4159-5.6575-11.4159-12.6535s4.9755-12.6788,11.3907-12.6788,11.5169,5.708,11.4159,12.6788c-.101,6.9708-5.026,12.6535-11.3907,12.6535ZM84.3576,65.4144c-6.2637,0-11.3907-5.6575-11.3907-12.6535s4.9755-12.6788,11.3907-12.6788,11.4917,5.708,11.3906,12.6788c-.101,6.9708-5.026,12.6535-11.3906,12.6535Z';
export const discordViewBox = '0 0 126.644 96';
+10 -6
View File
@@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
export default function VersionSwitcher(): JSX.Element { export default function VersionSwitcher(): JSX.Element {
const [versions, setVersions] = useState([]); const [versions, setVersions] = useState([]);
const [label, setLabel] = useState('Versions'); const [activeLabel, setLabel] = useState('Versions');
const windowSize = useWindowSize(); const windowSize = useWindowSize();
@@ -24,10 +24,13 @@ export default function VersionSwitcher(): JSX.Element {
{ label: 'Next', url: 'https://main.preview.immich.app' }, { label: 'Next', url: 'https://main.preview.immich.app' },
{ label: 'Latest', url: 'https://immich.app' }, { label: 'Latest', url: 'https://immich.app' },
...archiveVersions, ...archiveVersions,
]; ].map(({ label, url }) => ({
label,
url: new URL(url),
}));
setVersions(allVersions); setVersions(allVersions);
const activeVersion = allVersions.find((version) => new URL(version.url).origin === window.location.origin); const activeVersion = allVersions.find((version) => version.url.origin === window.location.origin);
if (activeVersion) { if (activeVersion) {
setLabel(activeVersion.label); setLabel(activeVersion.label);
} }
@@ -44,13 +47,14 @@ export default function VersionSwitcher(): JSX.Element {
return ( return (
versions.length > 0 && ( versions.length > 0 && (
<DropdownNavbarItem <DropdownNavbarItem
className="navbar__item" className="version-switcher-34ab39"
label={label} label={activeLabel}
mobile={windowSize === 'mobile'} mobile={windowSize === 'mobile'}
items={versions.map(({ label, url }) => ({ items={versions.map(({ label, url }) => ({
label, label,
to: url, to: new URL(location.pathname + location.search + location.hash, url).href,
target: '_self', target: '_self',
className: label === activeLabel ? 'dropdown__link--active menu__link--active' : '', // workaround because React Router `<NavLink>` only supports using URL path for checking if active: https://v5.reactrouter.com/web/api/NavLink/isactive-func
}))} }))}
/> />
) )
+5
View File
@@ -75,6 +75,11 @@ div[class^='announcementBar_'] {
font-weight: 500; font-weight: 500;
} }
/* workaround for version switcher PR 15894 */
div[class*='navbar__items'] > li:has(a[class*='version-switcher-34ab39']) {
display: none;
}
code { code {
font-weight: 600; font-weight: 600;
} }
+22 -19
View File
@@ -1,12 +1,10 @@
import React from 'react'; import React from 'react';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import { useColorMode } from '@docusaurus/theme-common'; import { discordPath, discordViewBox } from '@site/src/components/svg-paths';
import { discordPath } from '@site/src/components/svg-paths'; import ThemedImage from '@theme/ThemedImage';
import Icon from '@mdi/react'; import Icon from '@mdi/react';
function HomepageHeader() { function HomepageHeader() {
const { isDarkTheme } = useColorMode();
return ( return (
<header> <header>
<div className="top-[calc(12%)] md:top-[calc(30%)] h-screen w-full absolute -z-10"> <div className="top-[calc(12%)] md:top-[calc(30%)] h-screen w-full absolute -z-10">
@@ -14,8 +12,8 @@ function HomepageHeader() {
<div className="w-full h-[120vh] absolute left-0 top-0 backdrop-blur-3xl bg-immich-bg/40 dark:bg-transparent"></div> <div className="w-full h-[120vh] absolute left-0 top-0 backdrop-blur-3xl bg-immich-bg/40 dark:bg-transparent"></div>
</div> </div>
<section className="text-center pt-12 sm:pt-24 bg-immich-bg/50 dark:bg-immich-dark-bg/80"> <section className="text-center pt-12 sm:pt-24 bg-immich-bg/50 dark:bg-immich-dark-bg/80">
<img <ThemedImage
src={isDarkTheme ? 'img/logomark-dark.svg' : 'img/logomark-light.svg'} sources={{ dark: 'img/logomark-dark.svg', light: 'img/logomark-light.svg' }}
className="h-[115px] w-[115px] mb-2 antialiased rounded-none" className="h-[115px] w-[115px] mb-2 antialiased rounded-none"
alt="Immich logo" alt="Immich logo"
/> />
@@ -35,7 +33,6 @@ function HomepageHeader() {
sacrificing your privacy. sacrificing your privacy.
</p> </p>
</div> </div>
<div className="flex flex-col sm:flex-row place-items-center place-content-center mt-9 gap-4 "> <div className="flex flex-col sm:flex-row place-items-center place-content-center mt-9 gap-4 ">
<Link <Link
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-primary dark:bg-immich-dark-primary rounded-xl no-underline hover:no-underline text-white hover:text-gray-50 dark:text-immich-dark-bg font-bold uppercase" className="flex place-items-center place-content-center py-3 px-8 border bg-immich-primary dark:bg-immich-dark-primary rounded-xl no-underline hover:no-underline text-white hover:text-gray-50 dark:text-immich-dark-bg font-bold uppercase"
@@ -50,28 +47,35 @@ function HomepageHeader() {
> >
Demo Demo
</Link> </Link>
</div>
<Link
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-primary/10 dark:bg-gray-300 rounded-xl hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase"
to="https://immich.store"
>
Buy Merch
</Link>
</div>
<div className="my-12 flex gap-1 font-medium place-items-center place-content-center text-immich-primary dark:text-immich-dark-primary"> <div className="my-12 flex gap-1 font-medium place-items-center place-content-center text-immich-primary dark:text-immich-dark-primary">
<Icon path={discordPath} size={1} /> <Icon
path={discordPath}
viewBox={discordViewBox} /* viewBox may show an error in your IDE but it is normal. */
size={1}
/>
<Link to="https://discord.immich.app/">Join our Discord</Link> <Link to="https://discord.immich.app/">Join our Discord</Link>
</div> </div>
<img <ThemedImage
src={isDarkTheme ? '/img/screenshot-dark.webp' : '/img/screenshot-light.webp'} sources={{ dark: '/img/screenshot-dark.webp', light: '/img/screenshot-light.webp' }}
alt="screenshots" alt="screenshots"
className="w-[95%] lg:w-[85%] xl:w-[70%] 2xl:w-[60%] " className="w-[95%] lg:w-[85%] xl:w-[70%] 2xl:w-[60%] "
/> />
<div className="mx-[25%] m-auto my-14 md:my-28"> <div className="mx-[25%] m-auto my-14 md:my-28">
<hr className="border bg-gray-500 dark:bg-gray-400" /> <hr className="border bg-gray-500 dark:bg-gray-400" />
</div> </div>
<ThemedImage
<img sources={{ dark: 'img/logomark-dark.svg', light: 'img/logomark-light.svg' }}
src={isDarkTheme ? 'img/logomark-dark.svg' : 'img/logomark-light.svg'}
className="h-[115px] w-[115px] mb-2 antialiased rounded-none" className="h-[115px] w-[115px] mb-2 antialiased rounded-none"
alt="Immich logo" alt="Immich logo"
/> />
<div> <div>
<p className="font-bold text-2xl md:text-5xl ">Download the mobile app</p> <p className="font-bold text-2xl md:text-5xl ">Download the mobile app</p>
<p className="text-lg"> <p className="text-lg">
@@ -90,9 +94,8 @@ function HomepageHeader() {
</a> </a>
</div> </div>
</div> </div>
<ThemedImage
<img sources={{ dark: '/img/app-qr-code-dark.svg', light: '/img/app-qr-code-light.svg' }}
src={isDarkTheme ? '/img/app-qr-code-dark.svg' : '/img/app-qr-code-light.svg'}
alt="app qr code" alt="app qr code"
width={'150px'} width={'150px'}
className="shadow-lg p-3 my-8 dark:bg-immich-dark-bg " className="shadow-lg p-3 my-8 dark:bg-immich-dark-bg "
-3
View File
@@ -1,10 +1,7 @@
import React from 'react'; import React from 'react';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import { useColorMode } from '@docusaurus/theme-common';
function HomepageHeader() { function HomepageHeader() {
const { isDarkTheme } = useColorMode();
return ( return (
<header> <header>
<section className="max-w-[900px] m-4 p-4 md:p-6 md:m-auto md:my-12 border border-red-400 rounded-2xl bg-slate-200 dark:bg-immich-dark-gray"> <section className="max-w-[900px] m-4 p-4 md:p-6 md:m-auto md:my-12 border border-red-400 rounded-2xl bg-slate-200 dark:bg-immich-dark-gray">
+7
View File
@@ -242,6 +242,13 @@ const roadmap: Item[] = [
]; ];
const milestones: Item[] = [ const milestones: Item[] = [
{
icon: mdiStar,
iconColor: 'gold',
title: '60,000 Stars',
description: 'Reached 60K Stars on GitHub!',
getDateLabel: withLanguage(new Date(2025, 2, 4)),
},
withRelease({ withRelease({
icon: mdiLinkEdit, icon: mdiLinkEdit,
iconColor: 'crimson', iconColor: 'crimson',
+67 -19
View File
@@ -1,4 +1,60 @@
[ [
{
"label": "v1.131.3",
"url": "https://v1.131.3.archive.immich.app"
},
{
"label": "v1.131.2",
"url": "https://v1.131.2.archive.immich.app"
},
{
"label": "v1.131.1",
"url": "https://v1.131.1.archive.immich.app"
},
{
"label": "v1.131.0",
"url": "https://v1.131.0.archive.immich.app"
},
{
"label": "v1.130.3",
"url": "https://v1.130.3.archive.immich.app"
},
{
"label": "v1.130.2",
"url": "https://v1.130.2.archive.immich.app"
},
{
"label": "v1.130.1",
"url": "https://v1.130.1.archive.immich.app"
},
{
"label": "v1.130.0",
"url": "https://v1.130.0.archive.immich.app"
},
{
"label": "v1.129.0",
"url": "https://v1.129.0.archive.immich.app"
},
{
"label": "v1.128.0",
"url": "https://v1.128.0.archive.immich.app"
},
{
"label": "v1.127.0",
"url": "https://v1.127.0.archive.immich.app"
},
{
"label": "v1.126.1",
"url": "https://v1.126.1.archive.immich.app"
},
{
"label": "v1.126.0",
"url": "https://v1.126.0.archive.immich.app"
},
{
"label": "v1.125.7",
"url": "https://v1.125.7.archive.immich.app"
},
{ {
"label": "v1.125.6", "label": "v1.125.6",
"url": "https://v1.125.6.archive.immich.app" "url": "https://v1.125.6.archive.immich.app"
@@ -7,10 +63,6 @@
"label": "v1.125.5", "label": "v1.125.5",
"url": "https://v1.125.5.archive.immich.app" "url": "https://v1.125.5.archive.immich.app"
}, },
{
"label": "v1.125.4",
"url": "https://v1.125.4.archive.immich.app"
},
{ {
"label": "v1.125.3", "label": "v1.125.3",
"url": "https://v1.125.3.archive.immich.app" "url": "https://v1.125.3.archive.immich.app"
@@ -23,10 +75,6 @@
"label": "v1.125.1", "label": "v1.125.1",
"url": "https://v1.125.1.archive.immich.app" "url": "https://v1.125.1.archive.immich.app"
}, },
{
"label": "v1.125.0",
"url": "https://v1.125.0.archive.immich.app"
},
{ {
"label": "v1.124.2", "label": "v1.124.2",
"url": "https://v1.124.2.archive.immich.app" "url": "https://v1.124.2.archive.immich.app"
@@ -189,46 +237,46 @@
}, },
{ {
"label": "v1.105.1", "label": "v1.105.1",
"url": "https://v1.105.1.archive.immich.app/" "url": "https://v1.105.1.archive.immich.app"
}, },
{ {
"label": "v1.105.0", "label": "v1.105.0",
"url": "https://v1.105.0.archive.immich.app/" "url": "https://v1.105.0.archive.immich.app"
}, },
{ {
"label": "v1.104.0", "label": "v1.104.0",
"url": "https://v1.104.0.archive.immich.app/" "url": "https://v1.104.0.archive.immich.app"
}, },
{ {
"label": "v1.103.1", "label": "v1.103.1",
"url": "https://v1.103.1.archive.immich.app/" "url": "https://v1.103.1.archive.immich.app"
}, },
{ {
"label": "v1.103.0", "label": "v1.103.0",
"url": "https://v1.103.0.archive.immich.app/" "url": "https://v1.103.0.archive.immich.app"
}, },
{ {
"label": "v1.102.3", "label": "v1.102.3",
"url": "https://v1.102.3.archive.immich.app/" "url": "https://v1.102.3.archive.immich.app"
}, },
{ {
"label": "v1.102.2", "label": "v1.102.2",
"url": "https://v1.102.2.archive.immich.app/" "url": "https://v1.102.2.archive.immich.app"
}, },
{ {
"label": "v1.102.1", "label": "v1.102.1",
"url": "https://v1.102.1.archive.immich.app/" "url": "https://v1.102.1.archive.immich.app"
}, },
{ {
"label": "v1.102.0", "label": "v1.102.0",
"url": "https://v1.102.0.archive.immich.app/" "url": "https://v1.102.0.archive.immich.app"
}, },
{ {
"label": "v1.101.0", "label": "v1.101.0",
"url": "https://v1.101.0.archive.immich.app/" "url": "https://v1.101.0.archive.immich.app"
}, },
{ {
"label": "v1.100.0", "label": "v1.100.0",
"url": "https://v1.100.0.archive.immich.app/" "url": "https://v1.100.0.archive.immich.app"
} }
] ]
Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

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