Compare commits

...

496 Commits

Author SHA1 Message Date
Alex The Bot
228a7710e6 Version v1.112.0 2024-08-14 15:51:18 +00:00
Alex
8014b0f86d chore(mobile): Translations update (#11771)
chore(mobile): translation update
2024-08-14 10:29:49 -05:00
Alex
fb962f49ea fix(ml): pydantic dep causes starting up issue (#11773)
* fix(ml): pydantic dep causes starting up issue

* revert import
2024-08-14 10:20:12 -05:00
ilyaChuk
7f7fec2cea feat(web): image editor - panel and cropping (#11074)
* cropping, panel

* fix presets

* types

* prettier

* fix lint

* fix aspect ratio, performance optimization

* improved tool selection, removed placeholder

* fix the mouse's exit from canvas

* fix error

* the "save" button and change tracking

* lint, format

* the mini functionality of the save button

* fix aspect ratio

* hide editor button on mobiles

* strict equality

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>

* Use the dollar sign syntax for stores inside components

* unobtrusive grid lines, circles at the corners

* more correct image load, handleError

* more strict equality

* fix styles. unused and tailwind

Co-Authored-By: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>

* dont store isShowEditor

* if showEditor - hide navbar & shortcuts

* crop-canvas decomposition (danger)

I could have accidentally broken something.. but I checked the work and it seems ok.

* fix lint

* fix ts

* callback function as props

* correctly disabling shortcuts

* convenient canvas borders

• you can use the mouse to go beyond the boundaries and freely change the crop.
• the circles on the corners of the canvas are not cut off.

* -the editor button for video files, -save button

* hide editor btn if panoramic || gif || live

* corners instead of circles (preview), fix lint&format

* confirm close editor without save

* vertical aspect ratios

* recovery after merge. editor's closing shortcut

* fix format

* move from canvas to html elements

* fix changes detections

* rotation

* hide detail panel if showing editor

* fix aspect ratios near min size

* fix crop area when changing image size when rotate

* fix of fix

* better layout - grouping

https://github.com/user-attachments/assets/48f15172-9666-4588-acb6-3cb5eda873a8

* hide the button

* fix i18n, format

* hide button

* hide button v2

---------

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-08-14 09:54:50 -05:00
Alex
593f036c0d fix(web): fallback aperture info when there is no locale set (#11770)
* fix(web): fallback aperture info when there is no locale set

* pr feedback
2024-08-14 15:52:44 +02:00
waclaw66
e934e368b3 fix(mobile): trash translations (#11761)
trash translations
2024-08-14 08:21:59 -05:00
renovate[bot]
f331a974ed chore(deps): update dependency @types/picomatch to v3.0.1 (#11755)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-13 23:06:46 -04:00
renovate[bot]
9d09b95618 chore(deps): update machine-learning (#11739)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-13 21:41:37 +00:00
Weblate (bot)
a8a63b24d0 chore(web): update translations (#11533)
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/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/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/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/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/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/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: AMT AMT <altmimiamt@gmail.com>
Co-authored-by: Adam Uchmanowicz <auchmanowicz@gmail.com>
Co-authored-by: António Santos <antoniomsantos99@gmail.com>
Co-authored-by: Atakan Dulker <atakandulker@gmail.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Christoph Auer <Christoph.Auer@pilsheim.de>
Co-authored-by: Cristian Florin Tănase <crissssty@gmail.com>
Co-authored-by: Czerjak N <czerjaknorbert@gmail.com>
Co-authored-by: Dmitry <kittyfriend@mail.ru>
Co-authored-by: Dmitry Banny <dj.icecore@gmail.com>
Co-authored-by: ElTopo <cameos@gmail.com>
Co-authored-by: Enoé Mugnaschi <enmuro@gmail.com>
Co-authored-by: Felipe Silva <dorsal-cobweb-life@duck.com>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Furkan Yutup <furkanyutupre@gmail.com>
Co-authored-by: Hugo Cossard <hugococa2004@gmail.com>
Co-authored-by: Ionut <ionutp626@gmail.com>
Co-authored-by: Joachim Klahr <joachim@klahr.se>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Lars Bernstein <lb@setq.de>
Co-authored-by: Laurentiu <laurfb@gmail.com>
Co-authored-by: Lauritz Tieste <lauritz6000000@gmail.com>
Co-authored-by: Luna Kowalik <0skar16.contact@gmail.com>
Co-authored-by: MM <metalmario90@gmail.com>
Co-authored-by: Majid <abtin.php@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki Mrvos <medolino2009@gmail.com>
Co-authored-by: Oliver Larsson <larsson.e.oliver@gmail.com>
Co-authored-by: Peder Kollenborg <pederkollenborg@gmail.com>
Co-authored-by: Pheggas <petko252@gmail.com>
Co-authored-by: Ponas <le.slab124@aleeas.com>
Co-authored-by: Pruthvi Bugidi <bps.21@proton.me>
Co-authored-by: Riccardo <lark-unit-rush@duck.com>
Co-authored-by: Rosu Iulian <rosuiulian@gmail.com>
Co-authored-by: Rıfat Dinç <rafidinc41@gmail.com>
Co-authored-by: Sam Smith <ja49619@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Simmer Lajos <weblate.linguini033@passinbox.com>
Co-authored-by: Simon Zeeck Svärd <simon.svard100@gmail.com>
Co-authored-by: Stan P <g97d6liib@mozmail.com>
Co-authored-by: TheScientistPT <joao.ed.reis.gomes@gmail.com>
Co-authored-by: Tobias Frejo <tobiasfrejo@gmail.com>
Co-authored-by: Tom Niget <zippedfire@free.fr>
Co-authored-by: UTKARSH VISHNOI <utkarshvishnoi25@gmail.com>
Co-authored-by: Varga Bence Levente <varga.bence.levente@protonmail.com>
Co-authored-by: Vincent Yeung <yeung_pok_yin_405060@yahoo.com.hk>
Co-authored-by: Vladimir Petrov (Vlado) <mr.vlado@gmail.com>
Co-authored-by: Voinea Laurentiu Gabriel <gabivoinea29@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: aarhor <aaron.horstmann9916@gmail.com>
Co-authored-by: anton <reallygud@protonmail.com>
Co-authored-by: chapvic <victor@chapaev.org>
Co-authored-by: dkorecko <reset259@gmail.com>
Co-authored-by: dvbthien <dvbthien@dvbthien.onmicrosoft.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: jocxfin <joonatan@joonatanh.com>
Co-authored-by: manosrh <manosrh@gmail.com>
Co-authored-by: oopzzozzo <ek3ru8m4@gmail.com>
Co-authored-by: pyorot <FMasic@hotmail.co.uk>
Co-authored-by: sibber5 <ghasjado@gmail.com>
Co-authored-by: thestrudl <rok.vidmar1997@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Åke Amcoff <ake@amcoff.net>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
Co-authored-by: 李奕寯 <eugenelego88@gmail.com>
2024-08-13 20:48:17 +00:00
Jason Rasmussen
ab0ed11778 chore: separate enhancement group in release notes (#11756) 2024-08-13 16:39:25 -04:00
Alex
5ec407b57c chore(mobile): properly patch openapi with custom response dto (#11753) 2024-08-13 14:39:25 -05:00
martin
fdf0b16fe3 feat(web): add privacy step in the onboarding (#11359)
* feat: add privacy step in the onboarding

* fix: remove console.log

* feat:Details the implications of enabling the map on the settings page

Added a link to the guide on customizing map styles as well

* feat: add map implication

* refactor: onboarding style

* fix: tile provider

* fix: remove long explanations

* chore: cleanup

---------

Co-authored-by: pcouy <contact@pierre-couy.dev>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
2024-08-13 17:01:30 +00:00
Pierre Couy
c924f6c27c docs: update custom map style guide (#11350)
* docs:Reword "Custom Map Style" guide

- Split setting a style.json in Immich and creating a style with
  Maptiler
- Make it clearer that this is the way to change tile provider

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2024-08-13 16:05:36 +00:00
Carsten Otto
df45ef0e35 fix(server): follow symlinks when zipping assets (#11685)
* follow symlinks when zipping assets

fixes #9335

* chore: clean up

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2024-08-13 11:39:24 -04:00
renovate[bot]
81c813a882 chore(deps): update dependency tailwindcss to v3.4.9 (#11750)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-13 11:37:06 -04:00
Michel Heusschen
b014162088 refactor(web): add tailwind plugin for repeating grid cols (#11748) 2024-08-13 11:36:46 -04:00
Michel Heusschen
276101ee82 feat(web): improve shared link management on mobile (#11720)
* feat(web): improve shared link management on mobile

* fix format
2024-08-13 09:37:47 -05:00
renovate[bot]
9837d60074 chore(deps): update dependency vite-tsconfig-paths to v5 (#11746)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-13 08:40:22 -04:00
renovate[bot]
28b7443b92 chore(deps): update base-image to v20240813 (major) (#11747)
chore(deps): update base-image to v20240813

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-13 12:26:22 +00:00
Michel Heusschen
5acdc958b6 fix(web): single row of items (#11729)
* fix(web): single row of items

* remove filterBoxWidth

* slight size adjustment

* rewrite action as component
2024-08-13 08:20:08 -04:00
renovate[bot]
e384692025 chore(deps): update typescript-projects (#11743)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-13 08:17:17 -04:00
renovate[bot]
54b276c984 chore(deps): update dependency @types/node to ^20.14.14 (#11737)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-12 23:31:57 -04:00
Jason Rasmussen
7eb004bd00 chore: better release notes (#11726)
* chore: better release notes

* chore: remove 'tedious' commits
2024-08-12 14:49:07 -04:00
Michel Heusschen
c2965c4408 fix(web): detail panel out of sync when reopening (#11713)
* fix(web): detail panel out of sync when reopening

* extract event handler
2024-08-12 08:10:43 -04:00
Michel Heusschen
b749a68349 fix(web): hide import json button when using config file (#11714) 2024-08-12 07:40:31 -04:00
Michel Heusschen
30aa2c9b82 fix(web): use fallback image if shared asset isn't resized (#11704)
* fix(web): use fallback image if shared asset isn't resized

* remove test-data index file
2024-08-11 15:43:07 -04:00
Robert Schütz
9ed04588b8 chore(deps): update pydantic to v2 (#11701) 2024-08-11 12:23:11 -04:00
Michel Heusschen
7d320217b9 chore(web): remove unused file (#11696) 2024-08-11 08:01:37 -04:00
Michel Heusschen
efdf8bbca9 refactor(web): simplify some stores (#11695)
* refactor(web): simplify some stores

* make writable
2024-08-11 08:01:16 -04:00
Michel Heusschen
34c4fbf730 fix(web): asset viewer dynamic size (#11697) 2024-08-11 07:59:26 -04:00
Matthew Momjian
ca775ab3e9 docs: Update docs + example.env for DB_PASSWORD (#11678) 2024-08-09 21:36:32 +00:00
renovate[bot]
2dd5514043 chore(deps): update prom/prometheus docker digest to cafe963 (#11673)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-09 14:07:25 -04:00
Christoph Suter
f33dbdfe9a feat(web): add Exif-Rating (#11580)
* Add Exif-Rating

* Integrate star rating as own component

* Add e2e tests for rating and validation

* Rename component and async handleChangeRating

* Display rating can be enabled in app settings

* Correct i18n reference

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>

* Star rating: change from slider to buttons

* Star rating for clarity

* Design updates.

* Renaming and code optimization

* chore: clean up

* chore: e2e formatting

* light mode border and default value

---------

Co-authored-by: Christoph Suter <christoph@suter-burri.ch>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-08-09 17:45:52 +00:00
Saschl
b1587a5dee feat(mobile): darken screen on backup page (#11623)
* feat: keep screen active on backup

* show dialog

* improve dialog and use shared timer

* get rid of confirmation dialog

* fix timer logic

* fix: set timeout to 60 seconds

* fix: revert unwanted change

* fix: properly hide status bar

* remove unwanted change

* fix: properly restore status bar when waking up

* clean up

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-08-09 16:39:33 +00:00
Alex
501485d0b1 fix(mobile): incorrect remove action from the album assets detail view (#11671)
* fix(mobile): incorrect remove action from the album assets detail view

* better data structure
2024-08-09 09:51:08 -05:00
renovate[bot]
ed7f857975 chore(deps): update prom/prometheus docker digest to 497fe92 (#11669)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-09 10:00:50 -04:00
Alex
d346985457 chore(mobile): refactor detail panel (#11662)
* date time component

* rename to info_sheet

* simplify map info

* Edit datetime sheet

* fix janking when scroll on info sheet

* Location refactor

* refactor name

* Update date time after editing

* localize rebuild to smaller component

* restore advanced bottom sheet

* reassign EXIF back to local database

* remove print statements
2024-08-09 13:43:47 +00:00
bo0tzz
a144a1bec3 chore: add warning to media location env var (#11665) 2024-08-09 07:29:55 -04:00
Carsten Otto
9f318a9338 fix(docs): update documentation (#11655)
update documentation
2024-08-08 23:03:43 +00:00
Michel Heusschen
11f41099c3 chore(web): remove font-size of 17px (#11657) 2024-08-08 13:26:53 -05:00
Michel Heusschen
96481aae5d refactor(web): supporter badge (#11656)
* refactor(web): supporter badge

* add style lang
2024-08-08 14:02:44 -04:00
Michel Heusschen
4a42a72bd3 fix(server): use luxon for maxdate validator (#11651) 2024-08-08 09:02:39 -05:00
Michel Heusschen
66f2ac8ce3 fix(web): keep album description in sync (#11652) 2024-08-08 09:02:08 -05:00
dependabot[bot]
6b2de807a7 chore(deps): bump docker/build-push-action from 6.6.0 to 6.6.1 (#11646)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.6.0 to 6.6.1.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.6.0...v6.6.1)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-08 07:28:40 -04:00
Michel Heusschen
96f8050143 feat(web): improve group-tab accessibility (#11647)
feat(web): improve GroupTab accessibility
2024-08-08 07:28:24 -04:00
Zack Pollard
14689462f8 feat: change web asset detail map to zoom level 12.5 (#11643) 2024-08-07 23:38:02 +01:00
Matthew Mirvish
fb68da2b51 fix(server): avoid transcoding thumbnail streams (#11603)
Co-authored-by: mincrmatt12 <mincrmatt12@users.noreply.github.com>
2024-08-07 18:36:37 -04:00
Alex
720b9a286e chore(mobile): update other dependencies (#11641) 2024-08-07 14:09:56 -05:00
Alex
d93ccb1669 chore(mobile): update maplibre_gl dep (#11640) 2024-08-07 13:47:40 -05:00
Alex
c34fc4f2d1 fix(mobile): iOS crashing when download iCloud content (#11639) 2024-08-07 13:09:15 -05:00
Matthew Momjian
905a062a6e docs: how to decrease Redis logs (#11638) 2024-08-07 18:38:27 +01:00
renovate[bot]
aeed24b5b4 fix(deps): update typescript-projects (#11606)
* fix(deps): update typescript-projects

* fix: type error

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2024-08-07 15:45:30 +00:00
Johannes Groß
28ba22e8c1 fix(server): handle numeric 'Image Description' and 'Description' values (#11636)
* Made 'Image Description' and 'Description' type safe during exif parsing

* add test + update types

---------

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
2024-08-07 15:23:36 +00:00
Jason Rasmussen
5b64456f48 chore: more cursed knowledge (#11631)
* chore: more cursed knowledge

* chore: more cursed knowledge

* chore: rework footer
2024-08-07 09:54:57 -04:00
Jason Rasmussen
02fd6d22b3 chore: more cursed knowledge (#11630) 2024-08-07 12:36:30 +00:00
dependabot[bot]
10ed31d725 chore(deps): bump docker/build-push-action from 6.5.0 to 6.6.0 (#11629)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.5.0 to 6.6.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.5.0...v6.6.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 08:31:23 -04:00
Mert
23d4314eed chore(server): support pgvecto.rs 0.3.0 (#11624)
relax pgvecto.rs constraint
2024-08-06 23:04:55 -04:00
renovate[bot]
ea135cc310 chore(deps): update dependency @types/node to ^20.14.13 (#11604)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-06 22:59:26 -04:00
Saschl
745e1b003d feat(mobile): enable wakelock on backup page (#11621) 2024-08-06 17:13:11 -05:00
Alex
1dae622dbc chore(mobile): minor styling fix (#11619) 2024-08-06 14:39:07 -05:00
renovate[bot]
8ca24f0ef2 fix(deps): update dependency auto_route to v9 (#11566)
* fix(deps): update dependency auto_route to v9

* fix dep conflict

* linting

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-08-06 12:50:20 -05:00
renovate[bot]
f679021f0e fix(deps): update dependency share_plus to v10 (#11550)
* fix(deps): update dependency share_plus to v10

* resolve dep conflict

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-08-06 17:24:55 +00:00
i-am-a-teapot
65f5118bdd feat(web): Add stacking option to deduplication utilities (#11114)
* feat(web): Add stacking option to deduplication utilities

* Update web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte

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

* Fix prettier

* Draft for server side modifications. Endpoint for stacks (PUT,DELETE)

* Fix error

* Disable stakc button if less or more than one asset selected

* Remove unnecesarry log

* Revert to first commit

* Further Revert

* Actually Revert to Origin

* Only one stack button

* Update +page.svelte

* Fix optional arguments

* Fix Prettier

* Fix Linting

* Add stack information to asset view

* clean up

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-08-06 17:06:30 +00:00
renovate[bot]
9f4fad2a0f chore(deps): update base-image to v20240806 (major) (#11616)
chore(deps): update base-image to v20240806

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-06 12:57:03 -04:00
Michel Heusschen
325fb4b5d1 fix(server): video duration extraction (#11610) 2024-08-06 11:27:05 -05:00
Alex
f040c9fb38 chore(server): remove get person asset limit (#11597)
* chore(server): remover get person asset limit

* sql

* remove getPersonAsset endpoint

* remove getPersonAsset endpoint

* use search endpoint to get people

* fix: server test

* mobile linter

* fix: server test

* remove debuglog

* deprecated endpoint

* change page size on mobile

* revert max size

* fix test
2024-08-06 16:22:13 +00:00
Pruthvi Bugidi
0eacdf93eb feat(mobile): add support for material themes (#11560)
* feat(mobile): add support for material themes

Added support for custom theming and updated all elements accordingly.

* fix(mobile): Restored immich brand colors to default theme

* fix(mobile): make ListTile titles bold in settings main page

* feat(mobile): update bottom nav and appbar colors

* small tweaks

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-08-06 14:20:27 +00:00
renovate[bot]
20262209ce fix(deps): update dependency setuptools to v70 [security] (#11609) 2024-08-06 10:09:38 -04:00
Michel Heusschen
dd638ac207 fix(web): slideshow on iphone (#11599)
* fix(web): slideshow on iphone

* make requestFullscreen type optional
2024-08-06 08:34:17 -05:00
Mert
d5b23373c7 refactor(server): startup checks for vector extension (#11559)
* update update logic

refactor

* update tests

* get version range through repo method, make tests more static

* move "should work" test
2024-08-05 21:00:25 -04:00
renovate[bot]
9765ccb5a7 chore(deps): update machine-learning (#11605)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-05 21:00:00 -04:00
renovate[bot]
82d934d09d chore(deps): update dependency eslint to v9 (#11601)
* chore(deps): update dependency eslint to v9

* chore: migrate to eslint flat config files

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2024-08-05 16:13:16 -04:00
renovate[bot]
2821e0bf95 chore(deps): update typescript-eslint monorepo to v8 (major) (#11598)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2024-08-05 19:13:00 +00:00
Michel Heusschen
bb3d9b6306 chore(web): remove unused event type definitions (#11600) 2024-08-05 14:50:48 -04:00
Alex
c83df2686a fix(mobile): autofill (#11591) 2024-08-05 12:02:31 -05:00
Jason Rasmussen
94da5942bd feat(web): open in map view (#11592) 2024-08-05 10:25:53 -05:00
Alex
54d2c12fff feat(docs): privacy policy (#11535) 2024-08-05 10:06:01 -05:00
foxit64
64fcb25971 fix: dockerfile linter error (#11590)
fix yamllint

Co-authored-by: sysadmin <sysadmin@localhost>
2024-08-05 09:02:02 -05:00
Jason Rasmussen
7f03bd8440 chore: dockerfile casing (#11589)
chore: docokerfile casing
2024-08-05 07:51:30 -05:00
Jason Rasmussen
2974cdbbee chore: dockerfile casing (#11588) 2024-08-05 12:07:28 +00:00
Yuvraj P
f0677735fd fix(mobile): Naming fix for the edited file (#11503) 2024-08-04 23:48:02 -05:00
Stefan Berggren
bb78eb4c4b Add Immich Distribution to Community Projects page (#11576)
Signed-off-by: Stefan Berggren <nsg@nsg.cc>
2024-08-05 03:36:55 +00:00
Mert
4ed75f2ac9 refactor(server): add config events for clip (#11575)
use config events for clip, add tests

formatting
2024-08-04 21:00:36 +00:00
Mert
3f4b783889 chore: add healthcheck field to server and ml (#11573)
add healthcheck field to server and ml
2024-08-04 13:37:43 -05:00
renovate[bot]
3968d76a57 fix(deps): update machine-learning (#11320) 2024-08-03 09:24:09 -04:00
Zack Pollard
55b31d1ce2 chore(web): fix weblate and other cleanup (#11532) 2024-08-02 13:35:47 +00:00
oidq
37cc6fbf27 fix(web): prevent change-location suggestion race-condition (#11523)
When debouncer activated on deletion, the handleSearchPlaces() function
would fire a request with empty query. UI would then show Immich API error.
2024-08-02 05:52:17 +00:00
Weblate (bot)
899b8a0ce7 chore(web): update translations (#11458)
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/he/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hu/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ko/
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/ro/
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/tr/
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: Atakan Dulker <atakandulker@gmail.com>
Co-authored-by: Czerjak N <czerjaknorbert@gmail.com>
Co-authored-by: Dmitry Banny <dj.icecore@gmail.com>
Co-authored-by: ElTopo <cameos@gmail.com>
Co-authored-by: Enoé Mugnaschi <enmuro@gmail.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Laurentiu <laurfb@gmail.com>
Co-authored-by: Luna Kowalik <0skar16.contact@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Pheggas <petko252@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Vladimir Petrov (Vlado) <mr.vlado@gmail.com>
Co-authored-by: Voinea Laurentiu Gabriel <gabivoinea29@gmail.com>
Co-authored-by: chapvic <victor@chapaev.org>
Co-authored-by: dkorecko <reset259@gmail.com>
Co-authored-by: dvbthien <dvbthien@dvbthien.onmicrosoft.com>
Co-authored-by: oopzzozzo <ek3ru8m4@gmail.com>
Co-authored-by: 李奕寯 <eugenelego88@gmail.com>
2024-08-01 23:30:44 -04:00
Justin Forseth
d3a5490e71 feat(server): search unknown place (#10866)
* Allow submission of null country

* Update searchAssetBuilder to handle nulls

andWhere({country:null}) produces `"exifInfo"."country" = NULL`. We want
`"exifInfo"."country" IS NULL`, so we have to treat NULL as a special
case

* Allow null country in frontend

* Make the query code a bit more straightforward

* Remove unused brackets import

* Remove log message

* Don't change whitespace for no reason

* Fix prettier style issue

* Update search.dto.ts validators per @jrasm91's recommendation

* Update api types

* Combine null country and state into one guard clause

* chore: clean up

* chore: add e2e for null/empty city, state, country search

* refactor: server returns suggestion for null values

* chore: clean up

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
2024-08-02 03:27:40 +00:00
Michel Heusschen
3afb5b497f fix(web): correctly format future timeline dates (#11506) 2024-08-01 07:39:26 -04:00
Michel Heusschen
1f0f880ecb fix(web): websocket over ipv6 (#11508) 2024-08-01 07:36:31 -04:00
martyfuhry
2c05ceaf50 fix(server): external domain url validation (#11493)
* fix(web): Changes externalDomain to IsUrl()

* refactor(web): asset viewer actions (#11449)

* refactor(web): asset viewer actions

* motion photo slot and more refactoring

fix(web): Changes externalDomain to IsUrl()

---------

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
2024-07-31 14:09:30 -04:00
Yuvraj P
01f8b7e458 fix(mobile): Crop presets break crop rectangle #11462 (#11467)
Fix Issue 11464
2024-07-31 12:19:19 -05:00
Michel Heusschen
b73f7fe16f refactor: deduplicate MemoryType and ReactionType enums (#11479)
* refactor: deduplicate memorytype and reactiontype enums

* fix mobile
2024-07-31 12:08:31 -05:00
Michel Heusschen
281cfc95a4 refactor(web): asset viewer actions (#11449)
* refactor(web): asset viewer actions

* motion photo slot and more refactoring
2024-07-31 12:25:38 -04:00
renovate[bot]
3a3ea6135e chore(deps): update typescript-projects (#11437)
* chore(deps): update typescript-projects

* chore: formatting

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
2024-07-31 15:40:23 +00:00
Jason Rasmussen
c44271e9b2 fix(deps): vitest@2 (#11491) 2024-07-31 11:26:35 -04:00
Jason Rasmussen
86904a8382 feat(web): more languages (#11488) 2024-07-31 10:26:17 -04:00
renovate[bot]
cf54829b3b chore(deps): update dependency eslint-plugin-unicorn to v55 (#11435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-31 08:49:35 -04:00
dependabot[bot]
990627e00d chore(deps): bump stumpylog/image-cleaner-action from 0.7.0 to 0.8.0 (#11480)
Bumps [stumpylog/image-cleaner-action](https://github.com/stumpylog/image-cleaner-action) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/stumpylog/image-cleaner-action/releases)
- [Changelog](https://github.com/stumpylog/image-cleaner-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stumpylog/image-cleaner-action/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: stumpylog/image-cleaner-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-31 08:48:06 -04:00
Mert
41580696c7 feat(ml): add more search models (#11468)
* update export code

* add uuid glob, sort model names

* add new models to ml, sort names

* add new models to server, sort by dims and name

* typo in name

* update export dependencies

* onnx save function

* format
2024-07-31 04:34:45 +00:00
renovate[bot]
2423bb36c4 chore(deps): update grafana/grafana docker tag to v11.1.3 (#11451)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-31 00:09:13 -04:00
Ben McCann
82b899649d fix: make HTML valid (#11465) 2024-07-31 00:05:08 -04:00
Alex
8ee8450d18 chore(mobile): post release task (#11456) 2024-07-30 21:41:10 -05:00
dependabot[bot]
6d47d52b3c chore(deps): bump docker/setup-buildx-action from 3.5.0 to 3.6.1 (#11445)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.5.0 to 3.6.1.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.5.0...v3.6.1)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-30 16:22:11 -04:00
Alex The Bot
919fd7d41f Version v1.111.0 2024-07-30 19:06:39 +00:00
Alex
c2fdb6aab8 chores(mobile): Translations update (#11454)
chore(mobile): translation update
2024-07-30 14:03:04 -05:00
Weblate (bot)
b6c4da37fd chore(web): update translations (#11429)
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/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/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/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pl/
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/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: Atakan Dulker <atakandulker@gmail.com>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Dmitry Banny <dj.icecore@gmail.com>
Co-authored-by: Enoé Mugnaschi <enmuro@gmail.com>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Maciek S <maslanypotwor1@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Ponas <le.slab124@aleeas.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Ultragian <giancarlo.brasil@gmail.com>
Co-authored-by: Unimpeded Lemur <yg7lh0fz3@mozmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: tddaij <xdaint@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
Co-authored-by: 李奕寯 <eugenelego88@gmail.com>
2024-07-30 14:01:42 -05:00
Alex
17c3e8e8bf fix(mobile): mobile logging out randomly (#11431)
* fix(mobile): refactor splash screen to not require online connection

* chore: bump flutter sdk path for vscode

* refactor: authentication provider always try network calls and only fail if 401 or no local user

* lint

* fix: revert change to lookup serverendpoint from store the isar store implementation is very broken

* fix: clear serverUrl and serverEndpoint on logout, and await logout call

* refactor: remove unneeded extra conditions in splash screen useEffect

* revert change to remove serverEndpoint on logging out

* pr feedback

---------

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2024-07-30 13:15:48 -05:00
renovate[bot]
21d3f248da chore(deps): update base-image to v20240730 (major) (#11447)
chore(deps): update base-image to v20240730

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-30 08:57:27 -04:00
renovate[bot]
a29660aae3 chore(deps): update dependency exiftool-vendored to v28 (#11440)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-30 07:30:25 -04:00
renovate[bot]
6c81fa0f0a fix(deps): update dependency exiftool-vendored to v28.2.0 (#11439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-30 07:29:31 -04:00
renovate[bot]
7156da502f chore(deps): update node.js to eb8101c (#11436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-29 22:53:17 -04:00
Alex
13741410a7 chore(mobile): Add text to bottom gallery bar (#11417) 2024-07-29 21:25:04 -05:00
Matthew Momjian
3408e6b3cb docs: warning to not edit volumes in compose (#11432)
* Update docker-compose.yml

* Update docker-compose.yml

* Update docker-compose.yml
2024-07-29 21:24:47 -05:00
Michel Heusschen
434bcec5cc fix(server): correct person birth date across timezones (#11369)
* fix(server): correct person birth date across timezones

* fix test

* update e2e tests

* use Optional decorator
2024-07-29 19:52:04 -04:00
Jason Rasmussen
ebc71e428d feat(server): reverse geocoding endpoint (#11430)
* feat(server): reverse geocoding endpoint

* chore: rename error message
2024-07-29 18:17:26 -04:00
eleith
a70cd368af fix(server): use fqdn for og:image meta tag value (#11082)
* attempt to use fqdn for og:image

opengraph image specifies that the url contains http or https, thus
implying a fqdn.

this change uses the external domain from the server config to attempt
to make the og:image have both the existing path to the thumbnail along
with the desired domain

if the server setting is empty, the old behavior will persist

please note, some og implementations do work with relative paths, so not
all og image checkers may still pass, but not all implementations have
this fallback and thus will not find the image otherwise

* tests and ssr for og:image value as fqdn

* formatting

* fix test

* formatting

* formatting

* fix tests

getConfig was requiring authentication. using already initiated global stores instead

* load config in shared link service itself

* join host and pathname/params safely

* use origin instead of host for full domain string

also fixes lint and address the imageURL type which is optional

* chore: clean up

---------

Co-authored-by: eleith <eleith@lemon.localdomain>
Co-authored-by: eleith <online-github@eleith.com>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
2024-07-29 21:38:47 +00:00
Jared L
3225e33fc1 feat(server): significantly improve Australian reverse geocoding accuracy (#11370)
chore(geocoding): ingest australia PPLXs
2024-07-29 10:59:53 -04:00
Weblate (bot)
85ab916ecf chore(web): update translations (#11416)
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/es/
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/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ru/
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: CraftWorks <weblate@craftworks.top>
Co-authored-by: Enoé Mugnaschi <enmuro@gmail.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: chapvic <victor@chapaev.org>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: nachtpfoetchen <nachtpfoetchen@posteo.de>
Co-authored-by: tddaij <xdaint@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: 李奕寯 <eugenelego88@gmail.com>
2024-07-29 14:48:44 +00:00
Michel Heusschen
7445dad0dd fix(web): timeline group date formatting (#11392)
* fix(web): timeline group date formatting

* add isValid check

* remove duplicate type
2024-07-29 10:42:55 -04:00
Michel Heusschen
0237f9baa3 feat(web): more localized number formatting (#11401) 2024-07-29 10:38:27 -04:00
Michel Heusschen
2e059bfbfd fix(web): avoid nesting buttons inside links (#11425) 2024-07-29 10:36:10 -04:00
renovate[bot]
7bb7f63d57 chore(deps): update dependency node to v20.16.0 (#11421)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-29 10:33:01 -04:00
renovate[bot]
66a5a5718f chore(deps): update terraform cloudflare to v4.38.0 (#11423)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-29 10:32:27 -04:00
Alex
ddc4d2f927 fix(mobile): client TLS on ios (#11415) 2024-07-28 17:32:53 -05:00
Weblate (bot)
0beeb61f5c chore(web): update translations (#11365)
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/cs/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/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/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pl/
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/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/tr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/uk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: AlrightIDidIt <fimofuni.igamunu@gotgel.org>
Co-authored-by: AxGD <guillermeaxel@yahoo.fr>
Co-authored-by: Bartłomiej Ruk <bartek04041993@gmail.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: ChoosenMEME <timjankowski259@gmail.com>
Co-authored-by: ConfusedAlex <alex@confusedalex.dev>
Co-authored-by: Coooolfan <coolfan1024@outlook.com>
Co-authored-by: Coxcopi70f00b67b61542fe <hn_vogel@gmx.net>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Eric Cornish <ao475129@gmail.com>
Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Gilgwath <gilgwath@protonmail.com>
Co-authored-by: Jakub <jakubula.jm@gmail.com>
Co-authored-by: Jordy H <jordy@hoebergen.net>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki Mrvos <medolino2009@gmail.com>
Co-authored-by: NikiTricky <niki.sto2010@gmail.com>
Co-authored-by: Sabin Oana <sabin.oana@gmail.com>
Co-authored-by: Sam Smith <ja49619@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: Varga Bence Levente <varga.bence.levente@protonmail.com>
Co-authored-by: Victor Sueiro <kiwicaja@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: aarhor <aaron.horstmann9916@gmail.com>
Co-authored-by: chapvic <victor@chapaev.org>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: krzemyk <krzemyk.official@proton.me>
Co-authored-by: nazo6 <git@nazo6.dev>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: yusufbarisk <yusufbarisk2004@gmail.com>
Co-authored-by: 李奕寯 <eugenelego88@gmail.com>
2024-07-28 20:53:04 +00:00
waclaw66
a321db9f48 fix(web): translation leftovers (#11412)
fix: new album
2024-07-28 15:43:25 -05:00
Matthew Momjian
827136fc8b docs: file custom location (#11413)
* file custom location

* fix microservices
2024-07-28 15:43:09 -05:00
Matthew Momjian
088eea88e0 docs: how to change PG PW (#11414)
* guide to change PG PW

* fix
2024-07-28 15:42:42 -05:00
Yuvraj P
15503784c8 feat(mobile): adds crop and rotate to mobile (#10989)
* Added Crop Feature

* Using LayoutBuilder Fix

* Using Immich Colors

* Using Immich Text Theme

* Chnaging dynamic datatype to nullable

* Fix for the retrivel of the image from the cropscreen

* Using Hooks State

* Small edits

* Finals edits

* Saving to the mobile

* Commented final code

* Commented final code

* Comments and AutoRoute

* Fix AutoRoute Final

* Naming tools and Action when made no edits

* Updating timeline after edit

* chore: lint

* format

* Light Mode Compatible

* fix duplicate page name

* Fix Routing

* Hiding the Button

* lint

* remove unused code

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-07-28 15:41:14 -05:00
Jonathan Jogenfors
bc8e236598 chore(server): make vite-tsconfig-paths a dev dependency instead (#11404) 2024-07-27 21:50:35 +02:00
Michel Heusschen
909bd43e65 fix(web): slideshow settings title (#11396) 2024-07-27 10:46:19 -05:00
Alex
3330885bcc chore(server): email template minor styling (#11387) 2024-07-26 21:58:48 -05:00
Jan
e1ac73718c feat(web): Duplicate-Page shortcut changes (#11183)
* duplicate page assign other shortcut keys, add 'open image' shortcut

* add shortcut info page to duplicates with own list of keys

* edit translations, add translationkeys

* format fix

* remove typo

---------

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-07-26 21:47:51 +00:00
Ben
a78eeb9b9c feat(web): search bar keyboard accessibility (#11323)
* feat(web): search bar keyboard accessibility

* fix: adjust aria attributes

* fix: safari announcing the correct option count

* minor adjustments

- CircleIconButton disabled cursor
- more generic selection handler

* fix: more subtle border color in dark mode

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-07-26 16:45:15 -05:00
martin
86b3e3ee13 fix(web): responsive design when selecting assets in an album (#11169)
fix: responsive design when selecting assets in an album
2024-07-26 16:33:20 -05:00
waclaw66
4b2bc8e4ce fix(mobile): search filter translation + fixes (#11141)
translation + fixes
2024-07-26 16:32:19 -05:00
renovate[bot]
f92aee204e chore(deps): update dependency @types/picomatch to v3 (#11096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-26 16:29:25 -05:00
renovate[bot]
7fd2b7965c chore(deps): update docker.io/redis:6.2-alpine docker digest to e3b17ba (#11302)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-26 16:28:34 -05:00
renovate[bot]
32ba6e3e3f chore(deps): update dependency byte-size to v9 (#11356)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-26 16:27:09 -05:00
Jonathan Jogenfors
0a6e5e0ec1 fix(server): make vitest pick up edited files (#11385)
fix vitest on file edit
2024-07-26 16:26:38 -05:00
Jonathan Jogenfors
65a4f86154 chore: bump vitest to 1.6.0 (#11386)
bump vitest to 1.6.0
2024-07-26 16:26:17 -05:00
ayykamp
147c6e3600 chore(web): improve responsiveness in Album and Shared Album pages on small devices (#11055)
* style: better responsiveness on album and shared album pages

* revert right margin changes

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-07-26 21:06:08 +00:00
Nicolò
ee6f1a010c chore(server): clean mail-templates and add tailwind style (#11296)
With this commit I wanted to complete the react-mail
 structure by properly define the templates styles by
 including tailwind css framework.

The framework is extended by both react-mail and
 tailwindcss-preset-email. Those packages help the rendering
 for various email clients.

If in future there is the necessity to target specific mail
 clients the package `tailwindcss-email-variants` and
 `tailwindcss-mso` can help too. The latter has some
 workarounds for the Ms Outlook that is still lacking
 a lot of the CSS3 funcitonality.
 to target

Signed-off-by: hitech95 <nicveronese@gmail.com>
2024-07-26 15:41:11 -05:00
renovate[bot]
a444ea7361 chore(deps): update dependency flutter to v3.22.3 (#11301)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-26 15:39:33 -05:00
Alex
59b809012f chore(mobile): post release task (#11382) 2024-07-26 15:38:41 -05:00
Ben
c037a8b8fa fix(web): easier alt text translation for other languages (#11124)
* fix(web): alt text translation for non-English languages

* fix: refactor to use full translation key names

* fix: calling the translation function directly
2024-07-26 13:48:40 -05:00
Michel Heusschen
ce15cf6065 fix(web): buy immich translations (#11379) 2024-07-26 13:41:59 -05:00
Alex The Bot
04340b3a62 Version v1.110.0 2024-07-26 15:38:20 +00:00
Alex
ef7a6bb246 chore(web): change license wording and other things (#11309) 2024-07-26 10:34:35 -05:00
Alex
bc20710c6d chore(mobile): Translations update (#11373)
chore(mobile): translation update
2024-07-26 10:31:10 -05:00
Zack Pollard
a63490a23b feat: use immich hosted map tiles (#11332) 2024-07-26 15:41:09 +01:00
Nicolò
a3799b3053 feat(server): add IP trust list for reverse proxy (#11286)
* feat(server): add IP trust list for reverse proxy

Signed-off-by: hitech95 <nicveronese@gmail.com>

* feat(docs): add documentation of `IMMICH_TRUSTED_PROXIES` env

Signed-off-by: hitech95 <nicveronese@gmail.com>

---------

Signed-off-by: hitech95 <nicveronese@gmail.com>
2024-07-26 09:23:58 -05:00
Yun Jiang
ea5d6780f2 feat(mobile): Adding setting in mobile app to TLS client certificate (#10860)
* feat(mobile): Adding setting in mobile app to import TLS client certificate and private key

* Formating dart source code to pass dart format test

* Adding missed required trailing commas to pass dart static analysis

* update lock file

* variable names

---------

Co-authored-by: Yun Jiang <yjiang@roku.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-07-26 13:59:02 +00:00
Saschl
62ac9bb7cd fix(mobile): native share functionality on iPad (#11294)
* pass context to share method

* use correct context

* fix: multiselection and logs sharing

* fix: lint
2024-07-26 08:43:59 -05:00
Michel Heusschen
86a658b891 fix(mobile): negative coordinate input (#11292)
* fix(mobile): negative coordinate input

* format
2024-07-26 08:37:29 -05:00
aviv926
536628ad95 docs: Add missing info to asset types and storage locations (#11358)
first
2024-07-26 08:34:36 -05:00
Jordy
2c7db0122d fix(mobile): changed "x jaren" to "x jaar" in dutch app translations (#11371)
changed "x jaren" to "x jaar"
2024-07-26 08:29:59 -05:00
Stephen Smith
ade2901259 feat(server): Allow activating non-admin user with server license (#11206)
* feat(server): allow server license to activate a user

* feat(web): send server+client licenses to user activation when non-admin

* chore(server): update test to allow server license to activate user

* fix(web): correctly load user to determine where to save license
2024-07-25 23:27:44 -05:00
imakida
d180373ec1 fix: "acess" should be "access" (#11363) 2024-07-26 03:36:01 +00:00
Weblate (bot)
c2a65d8fac chore(web): update translations (#11165)
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/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/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/ja/
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/nl/
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/sk/
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/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: Alex <alex@guldager.one>
Co-authored-by: Alexandr Zhytnyk <oper.kh@gmail.com>
Co-authored-by: AlrightIDidIt <fimofuni.igamunu@gotgel.org>
Co-authored-by: António Santos <antoniomsantos99@gmail.com>
Co-authored-by: Arkady Titenko <pgp-noreply@rkd.dev>
Co-authored-by: Aurora <arci@anche.no>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Coooolfan <coolfan1024@outlook.com>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Digital <github@crni.xyz>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Emerson Guimaraes <emersonrosa13@proton.me>
Co-authored-by: Filip Bredborg <fbredborg@gmail.com>
Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Jaksa <jaks@hotmail.de>
Co-authored-by: Joar von Arndt <joarxpablo@gmail.com>
Co-authored-by: Julien SORIN <julien.sorin@hotmail.fr>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Lauritz Tieste <lauritz6000000@gmail.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Lukas Miskovsky <miskovskylukas@gmail.com>
Co-authored-by: MATTENN <at.mattenn@gmail.com>
Co-authored-by: Majid <abtin.php@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Mansour Javaher <info@mansour.co.nz>
Co-authored-by: Marko <anony253@live.com>
Co-authored-by: Martin Dechev <dechev86@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Mike <mike.tgv@gmail.com>
Co-authored-by: Miki Mrvos <medolino2009@gmail.com>
Co-authored-by: Mingyu Kim <mingyu@mingyu.co.kr>
Co-authored-by: Oton <oms.moreira@outlook.com>
Co-authored-by: PPNplus <ppnplus@protonmail.com>
Co-authored-by: Pheggas <petko252@gmail.com>
Co-authored-by: PolarisYHNL <polarisyhnl@yeah.net>
Co-authored-by: Ponas <le.slab124@aleeas.com>
Co-authored-by: Quang Dang <dangminhquang.r@gmail.com>
Co-authored-by: RaduTek <radutux13@gmail.com>
Co-authored-by: Riku Viitanen <riku.viitanen@protonmail.com>
Co-authored-by: Rolando Grave <roland@graved.ch>
Co-authored-by: Rookie Nguyễn <nguyenquocthang2004@gmail.com>
Co-authored-by: Sam Smith <ja49619@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Sophie <mail@sopht.li>
Co-authored-by: Thế Anh Hoàng <the.anh.ls@gmail.com>
Co-authored-by: Timothy <timothy@benker.cc>
Co-authored-by: Varga Bence Levente <varga.bence.levente@protonmail.com>
Co-authored-by: Vikram Pratap Singh <vicky18189@gmail.com>
Co-authored-by: Vincenzo Nunziata <vinciosdev@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: Yusuf Kenan Demiray <yusken2009@gmail.com>
Co-authored-by: aarhor <aaron.horstmann9916@gmail.com>
Co-authored-by: blomusti <m.f.varkara@gmail.com>
Co-authored-by: chapvic <victor@chapaev.org>
Co-authored-by: dvbthien <dvbthien@dvbthien.onmicrosoft.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: fenix_vd <mrfenixvd@yandex.ru>
Co-authored-by: fuzfyy <egeozce35@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: grgergo <gergo_g@proton.me>
Co-authored-by: mitakskia <spammitakskia@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Àlex Bravo <alexbravobosch@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
Co-authored-by: 李奕寯 <eugenelego88@gmail.com>
2024-07-25 19:28:48 -04:00
Michel Heusschen
8e6bc13540 feat: people infinite scroll (#11326)
* feat: people infinite scroll

* add infinite scroll to show & hide modal

* update unit tests

* show total people count instead of currently loaded

* update personsearchdto
2024-07-25 15:59:28 -04:00
renovate[bot]
152421e288 chore(deps): update redis:6.2-alpine docker digest to e3b17ba (#11303)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-25 15:20:11 -04:00
aviv926
72a8bbb874 docs: add product key to roadmap (#11351)
* add license to roadmap

* fix

* Supporter Badge

* fix
2024-07-25 19:16:56 +00:00
Zack Pollard
b8d2d38bd1 chore(docs): compress homepage screenshots, 10x smaller (#11347) 2024-07-25 14:50:00 +01:00
Jason Rasmussen
9f6ef92f0b fix(deps): exiftool-vendored (#11338) 2024-07-24 17:38:22 -04:00
renovate[bot]
9e60c107ca chore(deps): update node (#11322)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-24 16:13:24 -04:00
renovate[bot]
2179f83d63 chore(deps): update machine-learning (#11310)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-23 12:53:47 -04:00
renovate[bot]
b259095899 chore(deps): update node (#11300)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-23 08:22:15 -04:00
renovate[bot]
145ace0fa1 chore(deps): update base-image to v20240723 (major) (#11311)
chore(deps): update base-image to v20240723

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-23 08:21:35 -04:00
Michel Heusschen
7d3db11a5c feat(web): coordinate input for asset location (#11291) 2024-07-23 08:01:10 -04:00
Michel Heusschen
8725656fd2 fix(server): DateTimeOriginal overwrite issue with sidecar file (#11306)
* fix(server): DateTimeOriginal overwrite issue with sidecar file

* update unit test
2024-07-23 07:59:46 -04:00
renovate[bot]
6394b4a9a3 chore(deps): update machine-learning (#11299)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-22 22:05:16 -04:00
Nikhil Taneja
d0b3dd888b docs: corrected container port for immich_microservices (#11170) 2024-07-22 13:55:59 +00:00
Michel Heusschen
849bc6e3aa fix(server): correct openapi response type for getServerLicense() (#11261)
* fix(server): correct openapi response type for getServerLicense()

* return 404 error when license doesn't exist

* update e2e test
2024-07-22 08:50:45 -05:00
dependabot[bot]
3d7a9d79da chore(deps): bump docker/build-push-action from 6.3.0 to 6.5.0 (#11282)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 14:45:25 +01:00
dependabot[bot]
f7cc9517ba chore(deps): bump docker/setup-qemu-action from 3.1.0 to 3.2.0 (#11283)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 14:45:14 +01:00
dependabot[bot]
73305feb5b chore(deps): bump docker/setup-buildx-action from 3.4.0 to 3.5.0 (#11284)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 14:45:00 +01:00
Michel Heusschen
950cd5d996 fix(web): use fixed position for download and upload panel (#11279) 2024-07-22 08:40:43 -04:00
renovate[bot]
b53bd8c525 fix(deps): update machine-learning (#10740)
* fix(deps): update machine-learning

* update openvino options, cuda

* update openvino build

* fix indentation

* update minimum nvidia driver

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
2024-07-21 19:30:24 -04:00
Michel Heusschen
8b773a2b2e fix(server): exif description whitespace handling (#11249)
* fix(server): exif description whitespace handling

* remove trim optional chaining
2024-07-21 19:01:14 -04:00
Daniel Dietzler
1e8806854d docs: 40k stars! (#11265)
40k stars!
2024-07-21 16:19:17 -05:00
Mert
9d2d556200 feat(server): accepted video containers (#11274)
* add accepted container config

* update api

* mp4 option makes no sense

* add to transcoding settings

* wording

* updated spec config

* formatting
2024-07-21 21:14:23 +00:00
Daniel Dietzler
7ecdcb3bc0 fix(server): static mail attachment extension (#11254)
* fix: static file extension

* chore: unit tests
2024-07-20 19:00:46 -04:00
Fynn Petersen-Frey
54488b1016 feat(ml): improved ARM-NN support (#11233) 2024-07-20 15:59:27 -04:00
Alex
7c3326b662 chore(mobile): post release task (#11220) 2024-07-19 15:10:29 +00:00
Fynn Petersen-Frey
745b16e4b4 feat(mobile): remove asset from album in gallery view (#11184)
Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-07-19 10:07:36 -05:00
Alex
a469fe44a1 chore(docs): change some wording (#11201) 2024-07-18 16:52:45 -04:00
Alex The Bot
b9fc59ca9f Version v1.109.2 2024-07-18 19:33:29 +00:00
Alex
e005a123ba fix(web): user can remove server license (#11199) 2024-07-18 14:26:54 -05:00
renovate[bot]
cd63212118 chore(deps): update base-image to v20240718 (major) (#11194)
chore(deps): update base-image to v20240718

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-18 13:58:17 -05:00
Michel Heusschen
a9dd013daf fix(web): hide license popup after mouse leave (#11193) 2024-07-18 13:13:45 -05:00
Alex The Bot
01ba859567 Version v1.109.1 2024-07-18 17:55:58 +00:00
Mert
173c9070c8 fix(ml): re-add worker env (#11192)
re-add worker env
2024-07-18 17:50:52 +00:00
Saschl
d37e8ede3b feat: optionally generate thumbnails for invalid images (#11126) 2024-07-18 12:07:22 -04:00
Alex The Bot
c77702279c Version v1.109.0 2024-07-18 16:03:42 +00:00
Alex
ef0e1a81b9 feat(web): license UI (#11182) 2024-07-18 10:56:27 -05:00
Mert
88f62087fd chore(ml): set higher worker timeout for openvino (#11174) 2024-07-18 10:50:57 -04:00
pokjay
4f89195702 feat(server): country geocoding for remote locations (#10950)
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2024-07-18 13:27:07 +02:00
renovate[bot]
ee22bbc85c chore(deps): update base-image to v20240717 (major) (#11172)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-17 20:41:18 +00:00
Jason Rasmussen
66fae76af2 fix(server): delete large album (#11042)
fix: large album asset operations
2024-07-17 07:43:35 -04:00
renovate[bot]
f0d1dbccf4 chore(deps): update base-image to v20240716 (major) (#11144)
chore(deps): update base-image to v20240716

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-17 07:37:48 -04:00
waclaw66
a78365faab fix(web): more translations (#11167)
* item(s)

* search_by_filename

* filename example

* memory lane
2024-07-17 11:37:39 +00:00
Michel Heusschen
e3fd766e9b fix(web): byte units enum (#11161) 2024-07-17 07:25:06 -04:00
Weblate (bot)
c9c56ac600 chore(web): update translations (#11038)
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/es/
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/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/ja/
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/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/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/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: Andreas Gammelgaard Damsbo <andreas@gdamsbo.dk>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Carlo Zanocco <zanocco.carlo@gmail.com>
Co-authored-by: Christer Solstrand Johannessen <weblate@csj.no>
Co-authored-by: Damian Krysta <damian@krysta.dev>
Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Håkon Velsvik <temanor@proton.me>
Co-authored-by: Joachim Klahr <joachim@klahr.se>
Co-authored-by: João Gonçalves <jpcg89@gmail.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Leo Bottaro <weblate@leobottaro.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Matteo D <alex3025game@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki M <medolino2009@gmail.com>
Co-authored-by: Pavel Shamshin <odan@selaz.org>
Co-authored-by: Peter Suba <peter.suba@gmail.com>
Co-authored-by: PolarisYHNL <polarisyhnl@yeah.net>
Co-authored-by: Ponas <le.slab124@aleeas.com>
Co-authored-by: Sam Smith <ja49619@gmail.com>
Co-authored-by: Shjosan <shjosan@kakmix.co>
Co-authored-by: Simmer Lajos <weblate.linguini033@passinbox.com>
Co-authored-by: Unimpeded Lemur <yg7lh0fz3@mozmail.com>
Co-authored-by: Vincenzo Nunziata <vinciosdev@gmail.com>
Co-authored-by: Vykintas Vyšniauskas <vykintasv@gmail.com>
Co-authored-by: Wojtek Sobczak <mister.adalbert@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: nazo6 <git@nazo6.dev>
Co-authored-by: polar <polar8143@users.noreply.hosted.weblate.org>
Co-authored-by: tomtom <beub3u@gmail.com>
Co-authored-by: vytautas <immichtranslation.a03gn@simplelogin.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Àlex Bravo <alexbravobosch@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2024-07-16 18:11:00 -05:00
bo0tzz
f6da01cb96 chore: Update feature-request.yaml (#11150) 2024-07-16 17:26:39 -05:00
Zack Pollard
fb8d9d8c40 fix: downgrade exiftool-vendored to fix motion photo extraction (#11145)
* Revert "chore(server): update exiftool and migrate off deprecated method signatures (#10367)"

This reverts commit 1b67ea2d

* fix: downgrade exiftool-vendored to 26.0.0

* chore: change motionphoto filenames to be kebab-case

* test: add pixel 6 pro motionphoto e2e test case

* test: add pixel 8a motion photo

* chore: update test-assets submodule pointer
2024-07-16 19:55:51 +00:00
Zack Pollard
87e8c16a90 fix: #11131 storage migration not moving archived files after template change (#11139) 2024-07-16 10:58:04 +00:00
renovate[bot]
99fe7b809a chore(deps): update terraform cloudflare to v4.37.0 (#11132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-16 10:49:54 +01:00
renovate[bot]
04e6e879a2 chore(deps): update typescript-projects (#11129)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-15 23:53:41 -04:00
Matthew Momjian
dda9c0057b docs: install script note (#11122)
install script note
2024-07-15 18:54:16 -04:00
Mert
cc1235d4aa docs: facial recognition and general clean-up (#11106)
* add facial recognition docs, clean up existing info

* Update smart-search.md

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

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-07-14 21:08:16 -05:00
Mert
8193416230 feat(server): conditionally run facial recognition nightly (#11080)
* only run nightly if new person

* add tests

* use string instead of date

* update sql

* update tests

* simplify condition
2024-07-14 22:53:42 +00:00
Matthew Momjian
8863bd4e7d docs: cleanup external libraries (#11099)
* cleanup external libraries

* Update external-library.md

* Update external-library.md

* Update libraries.md

* Update docs/docs/features/libraries.md

Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>

* Update external-library.md

---------

Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
2024-07-14 17:29:47 -04:00
Raj Dave
d23aa5e8e2 fix(docs): minor grammar fix in external-library.md (#11073) 2024-07-14 02:09:28 +00:00
renovate[bot]
18b466ee52 chore(deps): update base-image to v20240713 (major) (#11066) 2024-07-13 20:58:21 -05:00
Alex
e852971a13 fix(mobile): fix database out of size (#11065) 2024-07-13 20:55:35 -05:00
renovate[bot]
fbe29bf4cd chore(deps): update dependency rimraf to v6 (#11079)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-13 21:45:45 -04:00
Michel Heusschen
5748f50c1f refactor(web): remove buffer package (#11058) 2024-07-12 16:40:57 +00:00
CanbiZ
1b3a7feb67 chore(docs): update German Readme (README_de_DE.md) (#11035)
Update README_de_DE.md

Update German Readme to newest version & improve some translations
2024-07-12 07:51:06 -04:00
Jason Rasmussen
d68bd876c1 chore: clean up change date form spacing (#11037) 2024-07-11 12:10:49 -04:00
Florian Karuhtz
c50ac55892 chore(web): use "immich-form-label" class for combobox label (#10254)
use "immich-form-label" class for combobox label
2024-07-11 11:23:58 -04:00
Adiel Tan
b2dd4e1c2b chore(docs): correct susceptible spelling (#11029)
Edit Spelling

https://dictionary.cambridge.org/dictionary/english/susceptible
2024-07-11 17:22:28 +02:00
CanbiZ
ff2ba240c9 feat(web): Rename the Menu Entry "admin.map_settings" to "admin.map_gps_settings" (#11033)
* Rename the Menu Entry "admin.map_settings" to "admin.map_gps_settings"

Explanation:
The main menu item is called Map & GPS-Settings. The sub-item below it is also called. 
It would be correct:

Main item:
Map & GPS-Settings
Sub-item 1:
Map settings

* Update en.json

* chore: formatting

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2024-07-11 15:20:57 +00:00
Weblate (bot)
96084355f0 chore(web): update translations (#11007)
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/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/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/ja/
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/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pl/
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/sk/
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/uk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/vi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: Alexandr Zhytnyk <oper.kh@gmail.com>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Henrik Lievonen <henrik.lievonen@hotmail.com>
Co-authored-by: HonKami <bjfl6jvkav@randomu.aleeas.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Lukas Miskovsky <miskovskylukas@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Marc Cizeron <marc@cizeron.me>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki M <medolino2009@gmail.com>
Co-authored-by: PolarisYHNL <polarisyhnl@yeah.net>
Co-authored-by: Ponas <le.slab124@aleeas.com>
Co-authored-by: RJS <skudru.rinalds@gmail.com>
Co-authored-by: Rookie Nguyễn <nguyenquocthang2004@gmail.com>
Co-authored-by: Sam Smith <ja49619@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Tyoda <tyoda@pm.me>
Co-authored-by: Ulices <hasecilu@tuta.io>
Co-authored-by: Unimpeded Lemur <yg7lh0fz3@mozmail.com>
Co-authored-by: Victor Sueiro <kiwicaja@gmail.com>
Co-authored-by: Vincenzo Nunziata <vinciosdev@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: guillezcurra <guillezcurra@gmail.com>
Co-authored-by: nazo6 <git@nazo6.dev>
Co-authored-by: opl- <jakub.trzy@op.pl>
Co-authored-by: vytautas <immichtranslation.a03gn@simplelogin.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Àlex Bravo <alexbravobosch@gmail.com>
Co-authored-by: Сергей Шагов <mrfenixvd@gmail.com>
2024-07-11 11:15:56 -04:00
Jason Rasmussen
25a380d023 feat(server): userinfo signing (#10756)
* feat(server): userinfo signing

* chore: e2e tests
2024-07-11 07:55:00 -04:00
CanbiZ
3cb42de931 feat(web): change mdiClose to mdiInfinity for User Management - quota (#11015)
Add Infinity Icon for Usermanagement (quota)

Add the "mdiInfinity" Icon instead of "mdiClose" for quota (0 for infinity)
2024-07-10 20:20:52 +00:00
Michel Heusschen
8dd1d95913 fix(web): prevent text wrapping for some languages (#11009) 2024-07-10 15:19:06 -05:00
Jason Rasmussen
0ee2390c7f docs: fix images (#11012) 2024-07-10 15:18:55 -05:00
MJ
52db9558b3 fix(doc): Fix broken link in Cursed Knowledge doc (#11008)
Fix broken link
2024-07-10 15:16:06 -04:00
Alex
0fbfbc86d2 chore(mobile): post release task (#11006) 2024-07-10 11:40:19 -05:00
Alex The Bot
c7432834d0 Version v1.108.0 2024-07-10 16:14:02 +00:00
Weblate (bot)
a971fae81f chore(web): update translations (#10961)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ar/
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/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/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/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pl/
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/sr_Latn/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sv/
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_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: Alexandr Zhytnyk <oper.kh@gmail.com>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Henrik Lievonen <henrik.lievonen@hotmail.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Lukas Miskovsky <miskovskylukas@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Marc Cizeron <marc@cizeron.me>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki M <medolino2009@gmail.com>
Co-authored-by: RJS <skudru.rinalds@gmail.com>
Co-authored-by: Rookie Nguyễn <nguyenquocthang2004@gmail.com>
Co-authored-by: Sam Smith <ja49619@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: guillezcurra <guillezcurra@gmail.com>
Co-authored-by: opl- <jakub.trzy@op.pl>
Co-authored-by: vytautas <immichtranslation.a03gn@simplelogin.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
2024-07-10 11:08:55 -05:00
Alex
a58a2eec53 fix(mobile): crash when navigate between large video files (#11002) 2024-07-10 10:30:27 -05:00
Mert
f43721ec92 fix(ml): armnn not being used (#10929)
* fix armnn not being used, move fallback handling to main, add tests

* formatting
2024-07-10 09:20:43 -05:00
Michel Heusschen
59aa347912 feat(web): render component in notifications (#10990) 2024-07-10 09:05:04 -05:00
Michel Heusschen
1dd1d36120 refactor(web): use callbacks for admin setting events (#10997) 2024-07-10 08:57:18 -05:00
Jason Rasmussen
545b206076 chore(server): remove unused code (#10999)
chore(sesrver): remove unused code
2024-07-10 09:46:52 -04:00
Michel Heusschen
cf77487c00 fix(server): skip smtp validation when there are no changes (#10991)
* fix(server): skip smtp validation when there are no changes

* rename test
2024-07-10 08:37:50 -04:00
renovate[bot]
9d8b755c07 chore(deps): update prom/prometheus docker digest to f20d312 (#10998)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-10 08:37:33 -04:00
Michel Heusschen
bd88b079ea fix(server): avoid server error for invalid email data type (#10978)
* fix(server): avoid server error for invalid email data type

* add e2e test

* fix e2e
2024-07-10 07:58:06 -04:00
renovate[bot]
27b13b82f5 chore(deps): update node (#10996)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-10 10:44:25 +00:00
renovate[bot]
79c8412660 chore(deps): update typescript-projects (#10975)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-10 11:40:03 +01:00
renovate[bot]
a078dde241 chore(deps): update base-image to v20240710 (major) (#10995)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-10 11:39:41 +01:00
renovate[bot]
7e4e96c440 chore(deps): update base-image to v20240709 (major) (#10956)
chore(deps): update base-image to v20240709

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-09 18:41:59 -04:00
Alex
94f129d632 chore(mobile): update photo_manager dep (#10965) 2024-07-09 10:52:58 -05:00
apeman
678111ed3b fix(server): wrong video rotation with QSV and RKMPP decoding (#10905) 2024-07-09 15:18:49 +00:00
renovate[bot]
c1036d6f88 chore(deps): update dependency node to v20.15.1 (#10969)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-09 06:56:25 -04:00
Zack Pollard
e8af0e859e chore: pin specific node version in .nvmrc (#10973) 2024-07-09 10:40:40 +00:00
Michel Heusschen
a0f6d7444a feat(web): improve show & hide people accessibility (#10954) 2024-07-08 22:42:12 -05:00
Simon Thiboutôt
eb89208abb feat(cli): use a queue for duplicate and upload (#10750)
* feat(cli): use a queue for duplicate and upload

Using a queue to process the files makes the file duplicate detection and asset upload more stable and tolerant of network errors. If an error occurs, the whole command will not stop; the task will be retried (3 times) before logging the error and moving to the next step.

The new queue abstraction is using [fastq](https://www.npmjs.com/package/fastq) internally.

* chore(cli): queue.push return promise which resolve with task

* test(cli): add spec for uploadFiles and checkForDuplicates
2024-07-08 22:39:07 -05:00
renovate[bot]
af94f0f979 chore(deps): update typescript-projects (#10962)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-08 22:03:15 -04:00
Weblate (bot)
025a54c462 chore(web): update translations (#10896)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ar/
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/es/
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/he/
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/ja/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ko/
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/ru/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sk/
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/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Henrik Lievonen <henrik.lievonen@hotmail.com>
Co-authored-by: Joachim Klahr <joachim@klahr.se>
Co-authored-by: Joel Calado <joelcalado@gmail.com>
Co-authored-by: Johan Olsson <joholsprivat@gmail.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Ján Melíšek <melisek.janko@gmail.com>
Co-authored-by: Lauri Koo <late91@gmail.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Majid <abtin.php@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Matteo D <alex3025game@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Nicholas <nicholasc0212@gmail.com>
Co-authored-by: Petri Hämäläinen <petri.hamalainen@mailbox.org>
Co-authored-by: Sam Smith <ja49619@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: coolstuff99 <aspasmoya@gmail.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: grgergo <gergo_g@proton.me>
Co-authored-by: lapourgagner <poubel125@gmail.com>
Co-authored-by: nazo6 <git@nazo6.dev>
Co-authored-by: opl- <jakub.trzy@op.pl>
Co-authored-by: pyorot <FMasic@hotmail.co.uk>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2024-07-08 19:41:38 -04:00
Jason Rasmussen
334a709cc6 refactor(server): partner search dto (#10902)
* refactor(server): partner search dto

* fix: missed reference

* mobile fix

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-07-08 16:41:39 -04:00
Jason Rasmussen
5f25e2ce82 refactor(server): build resources (#10958) 2024-07-08 14:53:18 -04:00
renovate[bot]
04d0f575b7 chore(deps): update dependency prettier-plugin-organize-imports to v4 (#10930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-07 22:17:06 -04:00
Michel Heusschen
e9683b326a refactor(web): show & hide people (#10933) 2024-07-07 20:33:59 -05:00
Michel Heusschen
cb40db9555 refactor(web): focus trap (#10915) 2024-07-07 20:33:07 -05:00
Ben
39221c8d1f chore(web): translate alt text (#10922)
* chore(web): translate image alt text

* fix: capitalize translations, improve unit test

* fix: unit testing against the actual en.json file

* fix: use derived store to generate alt text
2024-07-07 17:29:56 -05:00
Michel Heusschen
a5467d60ea fix(web): external library disk usage unit (#10935) 2024-07-07 07:21:17 -04:00
Michel Heusschen
d582ec02b1 fix(server): reset-admin-password command (#10939)
* fix(server): reset-admin-password command

* fix immichCli
2024-07-07 07:20:28 -04:00
Jason Rasmussen
59cdbdc492 refactor(server): use .toSorted (#10904) 2024-07-06 10:32:38 -04:00
Jason Rasmussen
01706ccf5c docs: cursed knowledge (#10907) 2024-07-06 00:02:07 -04:00
Jason Rasmussen
6c49a4ba34 fix(server): do not try to upgrade to an older version (#10903) 2024-07-05 17:50:01 -04:00
Jason Rasmussen
e1f25b44d2 refactor(server): stack owner (#10900) 2024-07-05 16:16:53 -04:00
Jordy
f6cafa3290 Update README_nl_NL.md (#10897) 2024-07-05 15:11:05 -04:00
Jason Rasmussen
53d4a5268b refactor(server): remove has asset (#10891) 2024-07-05 15:10:11 -04:00
Jason Rasmussen
cf88f4b6f8 refactor(server): bulk interface (#10889) 2024-07-05 14:58:34 -04:00
Jason Rasmussen
ac8d8d91f7 chore: add az language (#10890) 2024-07-05 13:24:03 -04:00
Weblate (bot)
842291124c chore(web): update translations (#10831)
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/cs/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fa/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/he/
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/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/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/tr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_Hant/
Translation: Immich/immich

Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Jaime Branco <jaimembranco@gmail.com>
Co-authored-by: Joachim Klahr <joachim@klahr.se>
Co-authored-by: Jonas Brenig <jonas.brenig@uni-wuerzburg.de>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Majid <abtin.php@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Michał Kulik <michal.kulik91@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki M <medolino2009@gmail.com>
Co-authored-by: Tim Krämer <weblate@tk22.de>
Co-authored-by: Vladimir <vladimir.stoev1015@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: cevirici <cevirici13@users.noreply.hosted.weblate.org>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: gokulvasanthgv <gokulvasanthstudies@gmail.com>
Co-authored-by: r926215 <evdrt01@gmail.com>
Co-authored-by: vytautas <immichtranslation.a03gn@simplelogin.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
2024-07-05 12:45:04 -04:00
immich-tofu[bot]
6f5b3c47b0 Added Code of conduct 2024-07-05 15:31:13 +00:00
Alex
b25642b889 fix(mobile): search picker overflow (#10870) 2024-07-05 09:47:33 -05:00
Alex
7bde19d842 chore(mobile): separate build flavors (#10872) 2024-07-05 09:43:11 -05:00
Jason Rasmussen
eb1ba11d60 refactor(server): rename asset stack to stack (#10828) 2024-07-05 09:08:36 -04:00
Michel Heusschen
23b3073687 fix(web): download archive for public user (#10877) 2024-07-05 09:08:14 -04:00
Michel Heusschen
3cd187dced refactor(web): use derived instead of get(t) (#10884) 2024-07-05 09:06:35 -04:00
dependabot[bot]
6791af8c2c chore(deps): bump docker/setup-buildx-action from 3.3.0 to 3.4.0 (#10843)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-05 11:58:20 +01:00
dependabot[bot]
e566fbb009 chore(deps): bump docker/setup-qemu-action from 3.0.0 to 3.1.0 (#10844)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-05 11:58:10 +01:00
Michel Heusschen
e5c92912fc chore(web): remove unused s function (#10878) 2024-07-05 11:51:52 +01:00
Michel Heusschen
f33d5b0a38 fix(web): duplicate thumbnail cover full width (#10880) 2024-07-05 11:51:28 +01:00
waclaw66
df10618a7e fix(mobile): exposure time display (#10842)
exposure time fix
2024-07-04 23:30:06 -05:00
Michel Heusschen
6030349a6f feat(web): use browser language by default (#10849) 2024-07-04 22:56:54 -05:00
waclaw66
6629bf50ae fix(web): user profile translation (#10851) 2024-07-04 22:55:40 -05:00
Michel Heusschen
e32ce82179 chore: remove unused snowburst one font (#10863) 2024-07-04 17:15:54 -04:00
renovate[bot]
10ea894186 chore(deps): update base-image to v20240702 (major) (#10821)
chore(deps): update base-image to v20240702

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-03 21:35:11 -05:00
Jason Rasmussen
81d12c0586 refactor(server): notification events (#10754) 2024-07-03 21:06:20 -05:00
Mert
0b88bef157 fix(server): face search migration sometimes failing (#10827)
* turn it off and back on

* handle missing smart search embedding column

* handle missing face embedding column

* simplify

* Revert "simplify"

This reverts commit 8322af0baf.

* fix migration
2024-07-03 21:02:43 -05:00
Weblate (bot)
2b8942026c chore(web): update translations (#10795)
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/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/es/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fa/
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/it/
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/lt/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lv/
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/ru/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sr_Latn/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sv/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/tr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: Andrii Solianyk <asolianik2015@gmail.com>
Co-authored-by: Anrijs J <ajargans@gmail.com>
Co-authored-by: Bartłomiej Ruk <bartek04041993@gmail.com>
Co-authored-by: Ben Tomsen <torben+554gc3ym@g-b.dk>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Ef <weblate.marina324@passmail.net>
Co-authored-by: Filip Bredborg <fbredborg@gmail.com>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Hoi <Hoihoi@users.noreply.hosted.weblate.org>
Co-authored-by: Joachim Klahr <joachim@klahr.se>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Majid <abtin.php@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Matteo D <alex3025game@gmail.com>
Co-authored-by: MattiaPell <mattiapellegrini16@gmail.com>
Co-authored-by: Pavel Shamshin <odan@selaz.org>
Co-authored-by: Rajat Patel <rajat@thenextgeek.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Stan P <g97d6liib@mozmail.com>
Co-authored-by: Sushil Kumar <sushilz25558@gmail.com>
Co-authored-by: Vladimir <vladimir.stoev1015@gmail.com>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: Yu-Kai \"Steven\" Wang <steven97102@gmail.com>
Co-authored-by: carcawey <dacarva@gmail.com>
Co-authored-by: cevirici <cevirici13@users.noreply.hosted.weblate.org>
Co-authored-by: idubnori <i.dub.nori@gmail.com>
Co-authored-by: pyorot <FMasic@hotmail.co.uk>
Co-authored-by: r926215 <evdrt01@gmail.com>
Co-authored-by: vytautas <immichtranslation.a03gn@simplelogin.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2024-07-03 21:21:02 -04:00
Jason Rasmussen
f5937a5a9b fix(web): delete library (#10822) 2024-07-03 17:09:15 -04:00
Jason Rasmussen
04f0ac1aad chore(web): remove unnused property (#10820) 2024-07-03 16:41:17 -04:00
Tom Vincent
4a481acca6 fix(server): Postgres -> Redis websocket (#10801) 2024-07-03 16:27:29 -04:00
Jason Rasmussen
de62bd3ba5 fix(server): healthcheck (#10811) 2024-07-03 11:27:03 -05:00
dependabot[bot]
ab2ea28ed9 chore(deps): bump docker/build-push-action from 6.2.0 to 6.3.0 (#10805)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 11:47:05 +01:00
Alex The Bot
96f29cefeb Version v1.107.2 2024-07-03 03:18:19 +00:00
Alex
6f950ea45d fix(mobile): incorrect translation string (#10794) 2024-07-02 22:13:22 -05:00
Alex
99c45bd4d2 fix(web): slow people page load (#10793) 2024-07-02 22:13:11 -05:00
Weblate (bot)
312030f275 chore(web): update translations (#10753)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ar/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ca/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/da/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/it/
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/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/sl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ta/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/th/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/vi/
Translation: Immich/immich

Co-authored-by: Alex van den Hoogen <alex3305@gmail.com>
Co-authored-by: Andrej Kralj <andrej.kralj@gmail.com>
Co-authored-by: Aurora <arci@anche.no>
Co-authored-by: Bartłomiej Ruk <bartek04041993@gmail.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Heine Olsen <olsen10051988@gmail.com>
Co-authored-by: Henrik Lievonen <henrik.lievonen@hotmail.com>
Co-authored-by: Jordi Masip <jordi@masip.cat>
Co-authored-by: Jordy H <jordy@hoebergen.net>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Justin Ruiter <weblate24@justinruiter.nl>
Co-authored-by: Maciek S <maslanypotwor1@gmail.com>
Co-authored-by: Majid <abtin.php@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: MiguelNdeCarvalho <geral@miguelndecarvalho.pt>
Co-authored-by: Nicolò <nicveronese@gmail.com>
Co-authored-by: Ryan Gleeson <gleeson.ryanj@gmail.com>
Co-authored-by: Vincenzo Nunziata <vinciosdev@gmail.com>
Co-authored-by: Ziemowit Zabawa <ziemek.zabawa@outlook.com>
Co-authored-by: dvbthien <dvbthien@dvbthien.onmicrosoft.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: nazo6 <git@nazo6.dev>
Co-authored-by: polar <polar8143@users.noreply.hosted.weblate.org>
Co-authored-by: wariw <wariwpl@gmail.com>
2024-07-02 22:03:20 -05:00
Alex
bed9ccadbc chore(mobile): post release pump (#10775) 2024-07-02 16:41:40 -05:00
renovate[bot]
d55499eba0 chore(deps): update typescript-projects (#10763)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-02 17:28:24 -04:00
Daniel Dietzler
910b75c6cc docs: fix typo in translations link (#10783) 2024-07-02 16:40:51 -04:00
Jason Rasmussen
6a11464d60 fix(server): do not allow merging a person into themselves (#10776) 2024-07-02 19:56:05 +00:00
Alex The Bot
aa29f5d69c Version v1.107.1 2024-07-02 19:04:29 +00:00
Alex
1ee10ee2d6 feat(mobile): Revert render assets on device by default (#10470) (#10774)
Revert "feat(mobile): render assets on device by default (#10470)"

This reverts commit 32da9d90e4.
2024-07-02 19:01:54 +00:00
Alex
f23401d911 fix(mobile): map crashes on Android (#10773)
Revert "fix(mobile): upgrade maplibre_gl package to fix issue with crash in ios7.4 above simulator (#10182)"

This reverts commit 99c6fdbc1c.
2024-07-02 13:43:52 -05:00
Alex
14d94df1b8 chore(mobile): post release pump (#10759)
* chore(mobile): post release pump

* remove cache report file
2024-07-02 11:20:52 -05:00
Alex The Bot
b47ec2f88f Version v1.107.0 2024-07-02 14:13:10 +00:00
Michel Heusschen
b5c8ca075c fix(web): scroll jank on memories page (#10752) 2024-07-02 11:59:11 +01:00
Harshith Goka
7bfa642fa3 feat(web): add keyboard shortcuts to duplicates utility (#10736)
SHIFT + K: Select keep all
SHIFT + T: Select trash all
SHIFT + C: Confirm selection
2024-07-02 11:32:53 +01:00
Weblate (bot)
9a83038728 chore(web): update translations (#10742)
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Luca De Falco <deffo89@gmail.com>
Co-authored-by: MSDNicrosoft <wang3311835119@hotmail.com>
Co-authored-by: Marcin Czop <marcin@czop.ru>
Co-authored-by: Mario <17320863+myanesp@users.noreply.github.com>
Co-authored-by: Patrick Bellasi <derkling@matbug.net>
Co-authored-by: Ryan Gleeson <gleeson.ryanj@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Sitram <adrian.martis@gmail.com>
Co-authored-by: Suryo Wibowo <nutzlichsein+github@gmail.com>
Co-authored-by: boman <boman.d@gmail.com>
Co-authored-by: cevirici <cevirici13@users.noreply.hosted.weblate.org>
Co-authored-by: polar <polar8143@users.noreply.hosted.weblate.org>
Co-authored-by: traptegies <lars.reuss@gmx.de>
2024-07-02 10:22:54 +00:00
renovate[bot]
a1629f0793 chore(deps): update docker/build-push-action action to v6.2.0 (#10745)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-02 11:11:15 +01:00
renovate[bot]
d4cba57102 fix(deps): update typescript-projects (#10744)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-02 11:10:56 +01:00
renovate[bot]
2934676594 chore(deps): update node (#10741)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-02 11:09:15 +01:00
dependabot[bot]
ebea793534 chore(deps): bump docker/build-push-action from 6.1.0 to 6.2.0 (#10655)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-02 11:08:34 +01:00
renovate[bot]
eeae77422f chore(deps): update terraform cloudflare to v4.36.0 (#10718)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-02 11:08:16 +01:00
Weblate (bot)
850424e960 chore(web): update translations (#10729)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/cs/
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/it/
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/ru/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/th/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/tr/
Translation: Immich/immich

Co-authored-by: Alessandro Saglia <github.eatery9779@bear-d.me>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Kirill Zhukov <siper13@gmail.com>
Co-authored-by: Majid <abtin.php@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Przemek <skweresp@gmail.com>
Co-authored-by: Ryan Gleeson <gleeson.ryanj@gmail.com>
Co-authored-by: cevirici <cevirici13@users.noreply.hosted.weblate.org>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2024-07-01 19:16:31 -04:00
Alex
58298bd038 docs: blog post July 2024 update (#10737) 2024-07-01 15:57:25 -05:00
Alex
e46af5c26b fix(web): activity status padding regression (#10734) 2024-07-01 15:06:46 -04:00
Zack Pollard
3b37b70626 feat(server): user and server license endpoints (#10682)
* feat: user license endpoints

* feat: server license endpoints

* chore: pr feedback

* chore: add more test cases

* chore: add prod license public keys

* chore: open-api generation
2024-07-01 17:43:16 +00:00
Alex
4193b0dede fix(web): suppress album upload notification (#10717)
* fix(web): suppress album upload notification

* restore translation strings
2024-07-01 13:19:57 -04:00
Michel Heusschen
ac51cad075 feat(web): html tags inside plural and select messages (#10696)
* feat(web): html tags inside plural and select messages

* add component docs
2024-07-01 11:54:13 -05:00
Alex
b54dd4e135 docs: Translations update (#10730)
chore(mobile): translation update
2024-07-01 09:44:15 -05:00
pyorot
f5164b42e0 fix(web): remove black bezels + better integrate ActivityStatus (#10667)
* remove black bezels + better integrate activity status

* remove justify-self-end + mr-4 → mr-3 (closer to desired spacing)

* clean up

* clean up some more

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-07-01 14:05:49 +00:00
Weblate (bot)
783088afbe chore(web): update translations (#10605)
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/de/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/he/
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/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/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/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/th/
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: Askolds Zusans <askolds.zusans@gmail.com>
Co-authored-by: AxGD <guillermeaxel@yahoo.fr>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Daniel <danielwichers@gmail.com>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Fredrik Ekdahl <fekdahl@gmail.com>
Co-authored-by: Ivan Naboichshikov <inaboichshikov@gmail.com>
Co-authored-by: JBP <weblate@1peer1boom.nl>
Co-authored-by: Jan <jan.widmer.ch@gmail.com>
Co-authored-by: Joachim Klahr <joachim@klahr.se>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Kirill Zhukov <siper13@gmail.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Londoneye02 <jcdelcaz@gmail.com>
Co-authored-by: Majid <abtin.php@gmail.com>
Co-authored-by: Manar Aldroubi <droubi@gmail.com>
Co-authored-by: Matteo <matteo.visintini@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Mihai Mura <mihai.mura.dev@gmail.com>
Co-authored-by: PPNplus <ppnplus@protonmail.com>
Co-authored-by: Patrick Williamson <patrickwill@me.com>
Co-authored-by: Pavel Shamshin <odan@selaz.org>
Co-authored-by: PolarisYHNL <polarisyhnl@yeah.net>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Son Do <son.do@merctrans.vn>
Co-authored-by: Stan P <g97d6liib@mozmail.com>
Co-authored-by: Ultragian <giancarlo.brasil@gmail.com>
Co-authored-by: Unimpeded Lemur <yg7lh0fz3@mozmail.com>
Co-authored-by: Vegard Skullerud <vegard@skullerud.net>
Co-authored-by: Victor Sueiro <kiwicaja@gmail.com>
Co-authored-by: Vincenzo Nunziata <vinciosdev@gmail.com>
Co-authored-by: YFrendo <yann.frendo@live.fr>
Co-authored-by: Yi Kuo <kuokuoyiyi@gmail.com>
Co-authored-by: Yusuf Mohammed <yousufinternet@gmail.com>
Co-authored-by: alien75 <thomas@imolesi.it>
Co-authored-by: carcawey <dacarva@gmail.com>
Co-authored-by: dvbthien <dvbthien@dvbthien.onmicrosoft.com>
Co-authored-by: dweissmueller <2868emerald@navalcadets.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: guillezcurra <guillezcurra@gmail.com>
Co-authored-by: nhy42 <paul.zanolin@gmail.com>
Co-authored-by: polar <polar8143@users.noreply.hosted.weblate.org>
Co-authored-by: pyorot <FMasic@hotmail.co.uk>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2024-07-01 08:54:33 -05:00
indam
744dfb675b docs: sync Chinese README with the official English version (#10724) 2024-07-01 09:27:35 +01:00
daniel bogachevsky
1d282851e2 fix(web): Sort timezones in assets settings by offset (#10697)
* fixed timezones on web are sorted alphabetically

* swaped order of operations in order to use DataTime.offset property for sorting

* optimization
2024-06-30 22:41:47 -05:00
Dawid Rejowski
d00d33d8a5 chore(doc): small punctuation fix backup-and-restore.md (#10704)
Small punctuation fix
2024-06-30 21:59:18 -05:00
Michel Heusschen
560dbd3c65 fix(web): shared link card (#10702) 2024-06-30 17:34:52 -05:00
Michel Heusschen
c58148af35 feat(web): add more translations (#10700)
* feat(web): add more translations

* formatting
2024-06-30 17:29:10 -05:00
bo0tzz
e54c18367b chore: Lower default duplicate detection distance (#10703) 2024-06-30 11:36:02 -04:00
Alex
8b6d27f1bc fix(server): show partners assets on timeline without permission (#10705)
* fix(server): show partners assets on timeline without permission

* save all

* correct fix
2024-06-29 22:45:59 -05:00
Alex
887acb9d9f chore(mobile): Revert "remove exclude album mechanism for backup (#10552)" (#10686)
Revert "chore(mobile): remove exclude album mechanism for backup (#10552)"

This reverts commit 5f47cf604a.
2024-06-29 11:30:18 -05:00
Michel Heusschen
8f553ddb39 fix(web): i18n race condition in load function (#10693) 2024-06-29 11:29:56 -05:00
Jason Rasmussen
24c1855899 fix: album remove asset bug (#10687)
* fix: album remove asset bug

* trigger GH Action

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-06-29 00:17:58 -04:00
Ben McCann
6ebae3c84f chore(deps): upgrade @testing-library/svelte (#10690) 2024-06-28 21:31:27 -04:00
martin
e0bb9add91 feat(web): use websocket to update the feature photo (#10683)
feat: use ws to update the feature photo
2024-06-28 14:40:18 -05:00
Pascal Sommer
821570f2fb feat(web): show favorite icon in duplicate asset (#10688)
* show favorite icon in duplicate asset

* remove isSharedLink check

* swap places of favorite icon and view button
2024-06-28 14:37:12 -05:00
Zack Pollard
a2364a12cf refactor: move /server-info endpoints to /server (#10677) 2024-06-28 17:08:19 +01:00
renovate[bot]
e361640e39 chore(deps): update grafana/grafana docker tag to v11.1.0 (#10679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-28 08:49:51 -04:00
martin
37b5d92110 fix(web): new feature photo (#9443)
* fix: new feature photo

* fix: use updatedAt
2024-06-27 20:16:26 -04:00
Matthew Momjian
325aa1d392 fix(docs): restart DB backup container (#10671)
Update backup-and-restore.md
2024-06-27 20:14:55 -04:00
Jason Rasmussen
72bf9439b0 refactor(server): event emits (#10648)
* refactor(server): event emits

* refactor: change default priority to 0
2024-06-27 15:54:20 -04:00
Jason Rasmussen
7e99394c70 fix(server): live photo relation (#10637)
* fix(server): live photo relation

* handle deletion and unit test

* lint

* chore: clean up and e2e tests

* fix test

* sql

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-06-27 14:41:49 -05:00
Miguel Domingues
8ff9c37d79 fix(web): match storage_template_migration_job with storage_template_migration (#10662) 2024-06-27 19:33:28 +00:00
Zhenzhen Zhao
0b4153e256 chore(trans): add zh-CN translations for custom proxy headers (#10660)
chore: add zh-CN translations for proxy headers

Signed-off-by: TripleZ <me@triplez.cn>
2024-06-27 13:38:51 -05:00
Michel Heusschen
12b9f3ad91 fix(server): about info version (#10659) 2024-06-27 12:36:25 -05:00
Jason Rasmussen
9fc9465cec feat(web): link router (#10644)
feat: link router
2024-06-27 09:09:28 -04:00
Alex
d8175d8da8 fix(mobile): asset state remain in gallery view after being deleted (#10603)
* fix(mobile): asset doesn't get removed from state renderList

* fix delete last assets

* refactor
2024-06-26 23:15:26 -05:00
Matej Kramny
922430da36 feat(mobile): add additional request headers (#10588)
* add additional request headers

* improve interface

* move headers under advanced settings

* refactor

* refactor

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-06-26 19:31:55 +00:00
Feng Kaiyu
a3c3619811 fix(cli): fix broken --album on Windows. (#10626)
Extract folder names via system function to avoid the difference between / and \ on Windows.
2024-06-26 11:12:30 -05:00
Pedro Ribeiro
7f5a3e5adb docs: Add new community guide to access Immich with a custom domain (#10638)
add new community guide to access immich with a custom domain

Co-authored-by: ppr88 <ppr88@local>
2024-06-26 10:55:27 -05:00
Jason Rasmussen
63041674c2 fix(server): user delete with stacked assets (#10642) 2024-06-26 09:29:52 -04:00
Jason Rasmussen
8a445cac07 chore: build metadata (#10612)
feat: build metadata
2024-06-26 08:25:09 -04:00
renovate[bot]
15c1cd6449 chore(deps): update dependency @types/node to ^20.14.7 (#10635)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 21:48:48 +00:00
renovate[bot]
8198259de8 chore(deps): update dependency typescript to v5.5.2 (#10633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 16:28:11 -04:00
Jason Rasmussen
6decf33226 chore: better auto labels (#10632) 2024-06-25 22:02:24 +02:00
renovate[bot]
df0064c83b chore(deps): pin node.js to 0ccc08f (#10628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 17:22:16 +01:00
Zack Pollard
c754f2504b chore: bump node docker versions (#10629) 2024-06-25 12:19:51 -04:00
renovate[bot]
0891658668 chore(deps): update base-image to v20240625 (major) (#10620)
chore(deps): update base-image to v20240625

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 12:18:38 -04:00
renovate[bot]
5b909eeaf0 chore(deps): update mambaorg/micromamba:bookworm-slim docker digest to 333f759 (#10631) 2024-06-25 16:18:27 +00:00
Zack Pollard
0484a4e252 chore: add renovate makefile command for testing renovate changes (#10630) 2024-06-25 12:18:02 -04:00
renovate[bot]
bf83fdee49 chore(deps): update terraform cloudflare to v4.35.0 (#10420)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 17:04:15 +01:00
renovate[bot]
9eafbb0524 fix(deps): update machine-learning (#10610) 2024-06-25 12:03:27 -04:00
Mert
6356c28f64 refactor(ml): model sessions (#10559) 2024-06-25 12:00:24 -04:00
Zack Pollard
6538ad8de7 chore: update docker node alpine versions to 3.20 (#10621) 2024-06-25 11:04:02 -04:00
renovate[bot]
9f9e42a96a chore(deps): update dependency prettier-plugin-svelte to v3.2.5 (#10623)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 11:03:29 -04:00
renovate[bot]
905d6c1508 chore(deps): update dependency @types/node to ^20.14.6 (#10627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 11:00:49 -04:00
Zack Pollard
91af793b52 ci: group docker node and npm node updates together (#10625)
also should fix @types/node not being correct versions
2024-06-25 15:49:50 +01:00
Zack Pollard
5912fcc393 ci: use .nvmrc for node-setup node-version in github actions (#10619)
* chore: add node version pinning with .nvmrc and volta for the typescript sdk

* ci: add missing setup-node actions and use .nvmrc for setup-node node-version
2024-06-25 14:01:15 +01:00
renovate[bot]
b5b0c6fe8b chore(deps): pin dependencies (#10618)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 11:22:38 +00:00
Jason Rasmussen
330648ff44 chore(deps): use full semver docker tag for node images (#10613)
* chore: use full semver docker tag for node images

* Update server/Dockerfile

Co-authored-by: bo0tzz <git@bo0tzz.me>

---------

Co-authored-by: bo0tzz <git@bo0tzz.me>
2024-06-25 11:12:27 +00:00
Junghyuk Kwon
54d1dc56a2 chore(docs): update Korean README (#10462)
* chore: update Korean README

* chore: correction

* chore(docs): update README_ko_KR.md

* chore: correction
2024-06-25 11:38:11 +01:00
renovate[bot]
d8e6b17ef9 fix(deps): update typescript-projects (#10616)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 11:14:15 +01:00
renovate[bot]
d7a33c8ec2 fix(deps): update typescript-projects (#10611)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-24 23:00:09 -04:00
Jason Rasmussen
0012369c67 chore: merge weblate (#10604) 2024-06-24 15:19:12 -04:00
waclaw66
cb3ac4ff9f chore(web): translation finetuning (#10601)
fixes
2024-06-24 15:05:45 -04:00
Weblate (bot)
4988df3fcb chore(web): update translations (#10593)
* chore(web): update translations

Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Immich <immich@futo.org>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Michał Kulik <michal.kulik91@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Stan P <g97d6liib@mozmail.com>
Co-authored-by: polar <polar8143@users.noreply.hosted.weblate.org>
Co-authored-by: pyorot <FMasic@hotmail.co.uk>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Translate-URL: https://hosted.weblate.org/projects/immich/immich/cs/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/fr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/id/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ko/
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/sr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ta/
Translation: Immich/immich

* chore: split serbian

---------

Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Immich <immich@futo.org>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Michał Kulik <michal.kulik91@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Stan P <g97d6liib@mozmail.com>
Co-authored-by: polar <polar8143@users.noreply.hosted.weblate.org>
Co-authored-by: pyorot <FMasic@hotmail.co.uk>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2024-06-24 15:04:53 -04:00
Jason Rasmussen
fc6c9a19d9 feat: more languages (#10595)
chore: more languages
2024-06-24 14:15:08 -04:00
Jason Rasmussen
13cc1f0aa6 docs: add private photos to roadmap (#10599)
docs: add locked photos to roadmap
2024-06-24 14:01:44 -04:00
Jason Rasmussen
ba72802888 chore: use immich.app email for security reports (#10594)
chore: use  immich.app email for security reports
2024-06-24 07:25:48 -07:00
RanKKI
04f0e29df6 fix(mobile): inconsistent thumbnail's label (#10589)
* fix(mobile): inconsistent thumbnail with label

* fix: limit person's name width
2024-06-24 07:24:57 -07:00
Jason Rasmussen
c83de5213f docs: add info about translations and weblate (#10591)
docs: update
2024-06-24 07:23:09 -07:00
waclaw66
dd2c7400a6 chore(web): another missing translations (#10274)
* chore(web): another missing translations

* unused removed

* more keys

* lint fix

* test fixed

* dynamic translation fix

* fixes

* people search translation

* params fixed

* keep filter setting fix

* lint fix

* $t fixes

* Update web/src/lib/i18n/en.json

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>

* another missing

* activity translation

* link sharing translations

* expiration dropdown fix - didn't work localized

* notification title

* device logout

* search results

* reset to default

* unsaved change

* select from computer

* selected

* select-2

* select-3

* unmerge

* pluralize, force icu message

* Update web/src/lib/components/asset-viewer/asset-viewer.svelte

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>

* review fixes

* remove user

* plural fixes

* ffmpeg settings

* fixes

* error title

* plural fixes

* onboarding

* change password

* more more

* console log fix

* another

* api key desc

* map marker

* format fix

* key fix

* asset-utils

* utils

* misc

---------

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
2024-06-24 09:50:01 -04:00
Weblate (bot)
df9e074304 chore(web): update translations (#10304)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ar/
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/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/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/ja/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ko/
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/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/
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/vi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: 2001 Y <yoshiki.tamura2001@gmail.com>
Co-authored-by: Abdullah <abdullahsalameh66@gmail.com>
Co-authored-by: Ahmad Malek <maichael.gt@gmail.com>
Co-authored-by: AlexMa2011 <alexma2011@outlook.com>
Co-authored-by: Alexis <alexisl61@outlook.fr>
Co-authored-by: Andrej Kralj <andrej.kralj@gmail.com>
Co-authored-by: AxGD <guillermeaxel@yahoo.fr>
Co-authored-by: Clément Roblot <clement.roblot@martobre.fr>
Co-authored-by: Coooolfan <coolfan1024@outlook.com>
Co-authored-by: Daddie0 <33762262+GoByeBye@users.noreply.github.com>
Co-authored-by: Dean Cvjetanović <forteee@gmail.com>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Denis Rebaud <denis@rebaud.fr>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Fanfouer <fanfouer@outlook.com>
Co-authored-by: Gustavo Ceolin <gustavogiulceolin@hotmail.com>
Co-authored-by: Hadrián Montes <hadrianmontes@gmail.com>
Co-authored-by: Héctor Martínez Juste <hectorzin@hotmail.com>
Co-authored-by: IM Ben <beniiorga@gmail.com>
Co-authored-by: Ignacy Kajdan <ignacy.kajdan@gmail.com>
Co-authored-by: Immich <immich@futo.org>
Co-authored-by: J1mooo <programingstafi@gmail.com>
Co-authored-by: JBP <weblate@1peer1boom.nl>
Co-authored-by: Jan <jan.widmer.ch@gmail.com>
Co-authored-by: JinYoung Park <norahc1999@gmail.com>
Co-authored-by: Jordi Masip <jordi@masip.cat>
Co-authored-by: Joseph <josephlegrand33+hosted.weblate.org@gmail.com>
Co-authored-by: Julien Deveaux <julien.deveaux@hotmail.com>
Co-authored-by: Julius969 <juliusdjorup@proton.me>
Co-authored-by: Junghyuk Kwon <kwon@junghy.uk>
Co-authored-by: Kentai Radiquum <kentai.waah@gmail.com>
Co-authored-by: Kovács Gergely <kgerg@duck.com>
Co-authored-by: Kyle Park <mysky3056@gmail.com>
Co-authored-by: Lauritz Tieste <lauritz6000000@gmail.com>
Co-authored-by: Leo Bottaro <github@leobottaro.com>
Co-authored-by: Leo Bottaro <weblate@leobottaro.com>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Linx <johnsmith_2003@hotmail.com>
Co-authored-by: Logge <hyper.xjo@gmail.com>
Co-authored-by: Maks s <smaks2313@gmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Max <Maxime.morasse@hotmail.fr>
Co-authored-by: Maximilian Waidelich <44324946+maxwai@users.noreply.github.com>
Co-authored-by: Michał Kulik <michal.kulik91@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki M <medolino2009@gmail.com>
Co-authored-by: Napat Srichan <napatsrichan2001@gmail.com>
Co-authored-by: Nick Götti <nick.goetti@outlook.com>
Co-authored-by: Patrick <patrickwill@me.com>
Co-authored-by: Pavel Shamshin <odan@selaz.org>
Co-authored-by: Peter Suba <peter.suba@gmail.com>
Co-authored-by: Petri Hämäläinen <petri.hamalainen@mailbox.org>
Co-authored-by: Pheggas <petko252@gmail.com>
Co-authored-by: PolarisYHNL <polarisyhnl@yeah.net>
Co-authored-by: Polly Julien <julien.polly@laposte.net>
Co-authored-by: Ptsa Daniel <ptsa1987@gmail.com>
Co-authored-by: Roukanken <kuko0411@gmail.com>
Co-authored-by: Ryan Gleeson <gleeson.ryanj@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Simmer Lajos <weblate.linguini033@passinbox.com>
Co-authored-by: Sleeper CH <sleeperch@gmail.com>
Co-authored-by: Sophie <mail@sopht.li>
Co-authored-by: Stan P <g97d6liib@mozmail.com>
Co-authored-by: Swayerka <admin@crozet.cc>
Co-authored-by: Tyoda <tyoda@pm.me>
Co-authored-by: ZtereoHYPE <57519662+ZtereoHYPE@users.noreply.github.com>
Co-authored-by: aln <imyapear@gmail.com>
Co-authored-by: carcawey <dacarva@gmail.com>
Co-authored-by: clementdelestre <clementdelestre@gmail.com>
Co-authored-by: dvbthien <dvbthien@dvbthien.onmicrosoft.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: grgergo <gergo_g@proton.me>
Co-authored-by: guillezcurra <guillezcurra@gmail.com>
Co-authored-by: ingria <codefuhrer@gmail.com>
Co-authored-by: mxm199 <mxm199@bk.ru>
Co-authored-by: myurar1a <sirometroid1235@outlook.jp>
Co-authored-by: opl- <jakub.trzy@op.pl>
Co-authored-by: pyorot <FMasic@hotmail.co.uk>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: wariw <wariwpl@gmail.com>
Co-authored-by: weiwhy <why1573920133@hotmail.com>
Co-authored-by: Àlex Garcia <alexgarciavila@gmail.com>
Co-authored-by: Алексей Меринов <merinov@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
Co-authored-by: Кирилл Москатов <kirillmoskatov@gmail.com>
2024-06-24 12:38:50 +00:00
Alex
5f47cf604a chore(mobile): remove exclude album mechanism for backup (#10552)
* chore(mobile): remove exclude album selection mechanism

* code generator

* code generator
2024-06-22 15:31:27 -07:00
dependabot[bot]
8e2f6f1f41 chore(deps): bump docker/build-push-action from 6.0.1 to 6.1.0 (#10522)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.0.1 to 6.1.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.0.1...v6.1.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-22 11:10:47 -07:00
Alex
32da9d90e4 feat(mobile): render assets on device by default (#10470)
* feat(mobile): render asset on device by default

* remove unused service
2024-06-22 09:13:05 -07:00
Michel Heusschen
6164640575 fix(web): FormatMessage development keys (#10536) 2024-06-22 09:08:56 -07:00
Feng Kaiyu
4cb165304b fix(cli): handle patterns correctly on Windows (#10430)
Modify the handling of patterns in the `crawl` function to correctly
convert the current path to a pattern when it contains backslash on
Windows, in according to fast-glob's docs.
2024-06-21 17:09:02 -07:00
renovate[bot]
1200265425 chore(deps): update docker.io/redis:6.2-alpine docker digest to 328fe6a (#10515)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-21 16:46:39 -04:00
renovate[bot]
0a3aafd439 chore(deps): update redis:6.2-alpine docker digest to 328fe6a (#10516)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-21 16:46:24 -04:00
Michel Heusschen
aaf7c0b6db fix(web): missing translations (#10504) 2024-06-21 13:09:10 -07:00
Michel Heusschen
b3252ffdac feat(web): translations containing html (#10491)
* feat(web): translations containing html

* add tests and more translations

* more translations

* rename FormatTags --> FormatMessage

* update version_announcement_message
2024-06-21 13:08:36 -07:00
Michel Heusschen
1129020159 fix(web): six digit year input (#10517) 2024-06-21 13:05:17 -07:00
erathmus
61a5d67674 feat(web): Adds sort order from album to shared album. (#10528) 2024-06-21 08:14:30 -07:00
Mert
42f3b50422 fix(server): /places entries sometimes not ordered alphabetically (#10514) 2024-06-20 23:48:19 -04:00
Daniel Dietzler
5e9a7b17d9 fix(server): allow library id to be null in metadata search (#10512)
* fix: allow library id to be null in metadata search

* chore: open api
2024-06-20 16:02:05 -07:00
Ben
0fda67543d chore(web): context menu improvements (#10475)
- ability to add custom hover colors
- migrate activity menu to ButtonContextMenu component
- onClick callbacks rather than events for menu options
- remove slots
- configurable menu option colors
- improve menu option layout
2024-06-20 14:15:36 -07:00
Michel Heusschen
5cde52eec9 feat(web): duplicate ui tweaks (#10506) 2024-06-20 14:14:34 -07:00
Matthew Momjian
eff839251c fix(deployment): Postgres healthcheck, add username to pg_isready (#10221) 2024-06-20 14:17:57 -04:00
Mert
a42af06889 fix(ml): limit load retries (#10494) 2024-06-20 14:13:18 -04:00
Mert
79a8ab71ef fix(server): reindex after changing to a model with a different dimension size (#10496)
reindex after truncating
2024-06-19 17:25:02 -04:00
Mert
1191978d50 fix(server): library refresh not checking trashed assets (#10495)
* set `withDeleted`

* update sql
2024-06-19 20:42:55 +00:00
renovate[bot]
7ea0278b32 chore(deps): update dependency eslint-plugin-unicorn to v54 (#10486)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-19 12:56:35 -04:00
renovate[bot]
4ef033aa55 chore(deps): update base-image to v20240618 (major) (#10457)
chore(deps): update base-image to v20240618

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-19 12:53:02 -04:00
dependabot[bot]
660afa9fad chore(deps): bump docker/build-push-action from 6.0.0 to 6.0.1 (#10483)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.0.0...v6.0.1)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 12:26:52 -04:00
dependabot[bot]
104048ecd5 chore(deps): bump ws and engine.io-client in /e2e (#10488)
Bumps [ws](https://github.com/websockets/ws) and [engine.io-client](https://github.com/socketio/engine.io-client). These dependencies needed to be updated together.

Updates `ws` from 8.11.0 to 8.17.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.11.0...8.17.1)

Updates `engine.io-client` from 6.5.3 to 6.5.4
- [Release notes](https://github.com/socketio/engine.io-client/releases)
- [Changelog](https://github.com/socketio/engine.io-client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/engine.io-client/compare/6.5.3...6.5.4)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
- dependency-name: engine.io-client
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 16:25:55 +00:00
dependabot[bot]
bec77f926e chore(deps): bump braces from 3.0.2 to 3.0.3 in /server (#10487)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 16:23:21 +00:00
renovate[bot]
ba57a1144d chore(deps): update prom/prometheus docker digest to 075b1ba (#10484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-19 12:20:58 -04:00
Mert
b3f9641edf feat(web): bulk deduplicate (#10448)
* bulk deduplicate

* notification for keeping all duplicates

* fix notification

* remove unused text

* pr feedback

* wording

* formatting
2024-06-19 12:11:59 -04:00
Mert
86cbc6e125 chore(ml): support python 3.12 (#10481) 2024-06-19 10:51:10 -04:00
Mert
968553a50e fix(server): video thumbnail generation failing with single i-frame (#10477) 2024-06-19 10:50:25 -04:00
Mert
5813dc02d1 fix(server): let thumbnail generation fail on error (#10479) 2024-06-19 10:50:09 -04:00
Mert
58b17a866b feat(web): display original heif images for safari (#10478) 2024-06-19 10:49:59 -04:00
renovate[bot]
c58b0ac66a chore(deps): update typescript-projects (#10445)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-19 07:39:25 -04:00
waclaw66
517a83cfa9 fix(web): comment send button (#10453) 2024-06-18 16:29:46 -07:00
renovate[bot]
7daa761eed chore(deps): update mambaorg/micromamba:bookworm-slim docker digest to b17c9b1 (#10465)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-18 19:05:26 -04:00
Mert
e58131492d fix(server): consider all I-frames for video thumbnails (#10471)
nointra instead of nokey
2024-06-18 19:02:33 -04:00
renovate[bot]
b21572cb32 chore(deps): update machine-learning (#10446)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-18 00:45:29 -04:00
renovate[bot]
8332efcd04 chore(deps): update dependency exiftool-vendored to v27 (#10447)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:03:23 -07:00
Ben
b71aa4473b feat(web): keyboard accessible context menus (#10017)
* feat(web,a11y): context menu keyboard navigation

* wip: all context menus visible

* wip: more migrations to the ButtonContextMenu, usability improvements

* wip: migrate Administration, PeopleCard

* wip: refocus the button on click, docs

* fix: more intuitive RightClickContextMenu

- configurable title
- focus management: tab keys, clicks, closing the menu
- automatically closing when an option is selected

* fix: refining the little details

- adjust the aria attributes
- intuitive escape key propagation
- extract context into its own file

* fix: dropdown options not clickable in a <Portal>

* wip: small fixes

- export selectedColor to prevent unexpected styling
- better context function naming

* chore: revert changes to list navigation, to reduce scope of the PR

* fix: remove topBorder prop

* feat: automatically select the first option on enter or space keypress

* fix: use Svelte store instead to handle selecting menu options

- better prop naming for ButtonContextMenu

* feat: hovering the mouse can change the active element

* fix: remove Portal, more predictable open/close behavior

* feat: make selected item visible using a scroll

- also: minor cleanup of the context-menu-navigation Svelte action

* feat: maintain context menu position on resize

* fix: use the whole padding class as better tailwind convention

* fix: options not announcing with screen reader for ButtonContextMenu

* fix: screen reader announcing right click context menu options

* fix: handle focus out scenario

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-06-17 20:52:38 -07:00
Muhideen Mujeeb Adeoye
99c6fdbc1c fix(mobile): upgrade maplibre_gl package to fix issue with crash in ios7.4 above simulator (#10182)
* fix(mobile): upgrade maplibre_gl package to fix issue with crash in ios7.4 above simulator

* chore: switch from deprecated widget and controller name to new name in latest sdk

* remove todo

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-06-17 22:27:54 +00:00
aviv926
c1a5ed3526 fix(web): Update prompt (#10237)
* update

* update

* update

* npm run format:fix
2024-06-17 15:24:04 -07:00
dependabot[bot]
9000ce4283 chore(deps): bump docker/build-push-action from 5.4.0 to 6.0.0 (#10433)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.4.0 to 6.0.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5.4.0...v6.0.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 13:11:55 -07:00
Alex
e8994d9ffd fix(web): confirm button is disabled if two dialogs are shown subsequently (#10440) 2024-06-17 11:44:25 -07:00
Stephen Smith
1b67ea2d91 chore(server): update exiftool and migrate off deprecated method signatures (#10367)
* chore(server): update exiftool and migrate off deprecated method signatures

* chore(server): update exiftool-vendored to 27.0.0

* chore(server): switch away from deprecated exiftool method signatures
- options now includes read/writeArgs making the deprecated signatures with
  args array redundant
- switch read call from file,args,options to file,options
- switch write call from file,tags,args to file,tags,options

* chore(server): move largefilesupport flags into exiftool constructor
- options now includes read/writeArgs making it available to be set globally in
  constructor
- switches back to instantiating an instance of exiftool

* chore(server): consolidate exiftool config into constructor along with writeArgs

* chore(server): move exiftool instantiation into MetadataRepository constructor
2024-06-17 10:11:11 -07:00
François-Guillaume Lemesre
38e26fd67c chore: update Unraid Docker-Compose documentation to reflect missing healthcheck start_interval parameter from Docker Engine v24.0.9. (#10406)
* Update Unraid Docker-Compose documentation to reflect missing healthcheck start_interval parameter from Docker Engine v24.0.9.

Unraid v6.12.10 uses Docker Engine v24.0.9, which does not support setting a start_interval parameter, used by the database container. Added info to the documentation to bypass this while retaining the initial health check interval.

* Fixed Markdown formatting.

* Removed info box formatting issue.

Moved the information about Unraid's Docker Engine version to section 4 of the installation instructions, instead of trying to use an info box that broke the formatting.

* fix format

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-06-17 17:08:31 +00:00
RanKKI
29e4666dfa fix(mobile): asset description is not shown on the sheet when opened for the first time (#10377)
* fix: invalidate asset's description when asset details changed

* refactor(exif-sheet): use description from exif instead

* refactor(asset-description): remove asset_description.provider

* fix(asset-description): set is empty based on exifInfo.description

* chore: rename service to provider
2024-06-17 10:01:02 -07:00
RanKKI
7ce87abc95 fix(mobile): my location button on maps not visible due to bottom padding (#10384)
fix(maps): my location button not visible due to bottom padding
2024-06-17 08:48:58 -07:00
RanKKI
eb987c14c1 fix(mobile): search page (#10385)
* refactor(search): hide people/places if empty

* refactor(search): remove unused stack

* refactor(search): fix dropdown menu's width

* feat(search): show camera make/model vertically on mobile devices

* fix: lint errors
2024-06-17 08:47:04 -07:00
Michel Heusschen
a6e767e46d fix(web): selecting shared link expiration (#10437) 2024-06-17 08:31:11 -07:00
Michel Heusschen
8e373cee8d fix(server): include archived assets in forced thumbnail generation (#10409) 2024-06-16 16:16:02 -04:00
Mert
6b1b5054f8 feat(server): separate face search relation (#10371)
* wip

* various fixes

* new migration

* fix test

* add face search entity, update sql

* update e2e

* set storage to external
2024-06-16 19:25:27 +00:00
RanKKI
0fe152b1ef fix(mobile): translation for title (#10324)
* fix(memory): translation for title

* chore: update memoery translation for dutch

* refactor(translation): avoid incompatibility with i18n website

* fix: lint errors
2024-06-16 15:54:15 +00:00
Mert
e77e87b936 fix(server): orientation handling for person thumbnails (#10382)
fix orientation handling
2024-06-16 08:45:58 -07:00
Michel Heusschen
0b08af7082 fix(web): update avatar color immediately (#10393) 2024-06-16 08:38:32 -07:00
Michel Heusschen
010eb1e0d6 fix(server): include trashed assets in forced thumbnail generation (#10389)
* fix(server): include trashed assets in forced thumbnail generation

* deleted -> trashed
2024-06-16 08:37:51 -07:00
Michel Heusschen
83a851b556 fix(web): play video muted when blocked by browser (#10383) 2024-06-16 08:37:25 -07:00
RanKKI
1cd51cc2de fix(app-bar): remove safe area of the app bar in photos page (#10340)
fix(app-bar): remove safe area of appbar in photos
2024-06-15 13:47:12 -07:00
Michel Heusschen
f3c15c7df8 feat(web): full screen view for duplicates (#10346)
* feat(web): full screen view for duplicates

* styling: make button visibility better

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2024-06-15 20:45:20 +00:00
Michel Heusschen
6a5435764e fix(web): allow sending test email when using config file (#10351)
fix(web): send test email when using config file
2024-06-15 12:14:28 -07:00
Michel Heusschen
dfad4f0ff4 fix(web): prevent new uploads from temporarily showing in trash (#10348) 2024-06-15 13:44:18 -04:00
Snowknight26
aea1c46bea feat(web): add cover images to individual shares (#9988)
* feat(web): add cover images to individual shares

* Update wording in share modal

* Use translation function

* Add and use new translations

* Fix formatting

* Update with suggestions

* Update test language

* Update test and language file per suggestions

* Fix formatting

* Remove unused translation
2024-06-14 19:16:48 -04:00
Jason Rasmussen
78f600ebce refactor(server): partner ids (#10321) 2024-06-14 18:29:32 -04:00
Daniel Dietzler
c896fe393f refactor(web): byte unit utils (#10332)
refactor byte unit utils
2024-06-14 17:27:46 +00:00
renovate[bot]
b4b654b53f fix(deps): update dependency exiftool-vendored to v26.2.0 (#10102)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-14 13:27:12 -04:00
Daniel Dietzler
dddc06c3b2 feat: user preferences for archive download size (#10296)
* feat: user preferences for archive download size

* chore: open api

* chore: clean up

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2024-06-14 11:27:12 -04:00
Matthew Momjian
596412cb8f docs: brief instructions to recover from corruption (#10319)
* brief instructions for corruption

* Update FAQ.mdx
2024-06-14 07:59:33 -05:00
renovate[bot]
e3a314b649 chore(deps): update node.js to eb17a08 (#10098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-14 02:34:08 -05:00
renovate[bot]
2bdb4bca9e chore(deps): update dependency flutter to v3.22.2 (#10158)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-14 02:33:27 -05:00
Ben
211451d234 chore(web): standardize settings labels (#10303)
* chore(web): standardize settings labels

- spelling out "max" and "min" in full
- accordions use title case
- labels for settings all use sentence case
- remove the "Enable"/"Enabled"/"ENABLED" titles for toggles, in favor
  of just using the description
- change any gray labels to be immich blue, to match the look and feel
  of the other settings

* chore: update user settings toggle, remove unused "enable" strings
2024-06-14 02:32:41 -05:00
Ronald Cantillo
e1731fe316 fix(doc): literal translation & missing parts (#10295) 2024-06-14 02:31:11 -05:00
renovate[bot]
ee186a40c2 fix(deps): update typescript-projects (#10105)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-13 20:46:26 -04:00
Weblate (bot)
32a0688028 chore(web): update translations (#10285)
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/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/hu/
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/lv/
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/ru/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/sr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/th/
Translation: Immich/immich

Co-authored-by: AxGD <guillermeaxel@yahoo.fr>
Co-authored-by: David Anes <david.anes@gmail.com>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Gustavo Ceolin <gustavogiulceolin@hotmail.com>
Co-authored-by: IM Ben <beniiorga@gmail.com>
Co-authored-by: Immich <immich@futo.org>
Co-authored-by: Jordy H <jordy@hoebergen.net>
Co-authored-by: Julius969 <juliusdjorup@proton.me>
Co-authored-by: Kyle Park <mysky3056@gmail.com>
Co-authored-by: Macgyver <macgyver@users.noreply.hosted.weblate.org>
Co-authored-by: Maks s <smaks2313@gmail.com>
Co-authored-by: Meliox <silent.ftp@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki M <medolino2009@gmail.com>
Co-authored-by: Napat Srichan <napatsrichan2001@gmail.com>
Co-authored-by: RJS <skudru.rinalds@gmail.com>
Co-authored-by: Samoht11 <thomasa24@gmail.com>
Co-authored-by: Sleeper CH <sleeperch@gmail.com>
Co-authored-by: Sophie <mail@sopht.li>
Co-authored-by: Thomas <thomas.ceccato.02@gmail.com>
Co-authored-by: carcawey <dacarva@gmail.com>
Co-authored-by: grgergo <gergo_g@proton.me>
Co-authored-by: kyu seok Park <tofinders@gmail.com>
Co-authored-by: mxm199 <mxm199@bk.ru>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Владислав Потаенко <vipotaenko02@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2024-06-14 00:35:49 +00:00
Daniel Dietzler
e5ed7d4af1 chore: update discord links (#10301)
update discord links
2024-06-13 20:27:01 -04:00
William Brockhus
30627fe91e chore: fix typo in jobs-workers.md (#10302) 2024-06-13 19:06:58 -04:00
Jason Rasmussen
77bd162872 fix(server): headers already send (#10289) 2024-06-13 13:30:34 -05:00
Jason Rasmussen
c6ab047167 fix(server): oauth linking error message (#10287) 2024-06-13 11:42:07 -04:00
Alex The Bot
8c2195c820 Version v1.106.4 2024-06-13 15:12:51 +00:00
Zack Pollard
5e99f651ec feat(web): add chinese (traditional), bislama and croatian to our supported languages (#10283)
* feat(web): add chinese (traditional), bislama and croatian to our supported languages

* test: remove language tag tests as it doesn't really test the correctness of tags
2024-06-13 15:00:55 +00:00
Weblate (bot)
0de15121f2 chore(web): update translations (#10224)
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/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/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/ko/
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/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/
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/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: Adrian <adrian.hundseth@gmail.com>
Co-authored-by: Andrej Kralj <andrej.kralj@gmail.com>
Co-authored-by: Ari <ayhavlin@gmail.com>
Co-authored-by: AxGD <guillermeaxel@yahoo.fr>
Co-authored-by: Beniamin Iorga <beniiorga@gmail.com>
Co-authored-by: BoBBer446 <eXestend@gmx.de>
Co-authored-by: Daddie0 <33762262+GoByeBye@users.noreply.github.com>
Co-authored-by: David Anes <david.anes@gmail.com>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Erik Mizenak <erikmizenak@gmail.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Fanfouer <fanfouer@outlook.com>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: J1mooo <programingstafi@gmail.com>
Co-authored-by: Jan <jan.widmer.ch@gmail.com>
Co-authored-by: Jordi Masip <jordi@masip.cat>
Co-authored-by: Kihoon Kim <kihoon.kim.dev@gmail.com>
Co-authored-by: Kyle Park <mysky3056@gmail.com>
Co-authored-by: Londoneye02 <jcdelcaz@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miki M <medolino2009@gmail.com>
Co-authored-by: Nega Duck <negaduck420@gmail.com>
Co-authored-by: Pavel Shamshin <odan@selaz.org>
Co-authored-by: Peter Suba <peter.suba@gmail.com>
Co-authored-by: Pheggas <petko252@gmail.com>
Co-authored-by: PolarisYHNL <polarisyhnl@yeah.net>
Co-authored-by: Pontus Österlindh <Pompe90@users.noreply.hosted.weblate.org>
Co-authored-by: Ptsa Daniel <ptsa1987@gmail.com>
Co-authored-by: Ryan Gleeson <gleeson.ryanj@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: SisyphusMD <guardian.note2892@fastmail.com>
Co-authored-by: ZHYang <i526842@gmail.com>
Co-authored-by: ZOKOB <remyfrichet@gmail.com>
Co-authored-by: Zack Pollard <zack@futo.org>
Co-authored-by: ZtereoHYPE <me@ztereohype.dev>
Co-authored-by: buck5060 <buck5060@gmail.com>
Co-authored-by: carcawey <dacarva@gmail.com>
Co-authored-by: dvbthien <dvbthien@dvbthien.onmicrosoft.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: grgergo <gergo_g@proton.me>
Co-authored-by: guillezcurra <guillezcurra@gmail.com>
Co-authored-by: kyu seok Park <tofinders@gmail.com>
Co-authored-by: mxm199 <mxm199@bk.ru>
Co-authored-by: opl- <jakub.trzy@op.pl>
Co-authored-by: pyorot <FMasic@hotmail.co.uk>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: yuuaHP <identity@yuua.dev>
Co-authored-by: Владислав Потаенко <vipotaenko02@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
Co-authored-by: 변준서 <four2mis@gmail.com>
2024-06-13 15:50:05 +01:00
Michel Heusschen
212ba35aef chore(web): translations in page load functions (#10260) 2024-06-13 09:23:52 -05:00
Richard Salame
827ec1b63a chore(doc): update quick-start.mdx (#10276)
Update quick-start.mdx

The following changes are made:

- Changed the headings to capital case.
- Changed a few sentences to sound more clear.
- Removed '?' from the heading as per the standards.
2024-06-13 09:23:02 -05:00
Alex
e2a2c86a31 chore(server): optional originalMimeType in asset response payload (#10272)
* chore(server): optional originalMimeType in asset response payload

* lint

* Update web/src/lib/utils/asset-utils.ts

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>

* fix permission of shared link

* test

* test

* test

* test server

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2024-06-13 09:21:47 -05:00
bo0tzz
df31eb1214 chore(docs): Delete unsupported SQL shenanigans (#10278) 2024-06-13 13:58:44 +00:00
Zack Pollard
0d6a4975a3 chore(web): remove unnecessary input.select for lang selector (#10273)
chore: remove unnecessary input.select for lang selector
2024-06-13 12:44:06 +00:00
Zack Pollard
7de2665344 fix(web): more language selector nits (#10271)
* fix: always sort development lang to bottom of list

* fix: clear search query in languages when box is clicked
2024-06-13 12:37:15 +01:00
bo0tzz
058ca28d88 feat(web): Language settings list UX nits (#10261)
* feat(web): Sort language settings list

before: https://bo0.tz/u/xMLnEW.png
after: https://bo0.tz/u/lGLn9h.png

* feat(web): Select combobox text when focused
2024-06-13 06:01:18 -05:00
Min Idzelis
b9593361a4 chore: additional makefile targets (#10243) 2024-06-13 05:58:44 -05:00
Michel Heusschen
a54e01ef2f fix: load original image for gifs (#10252) 2024-06-13 05:57:46 -05:00
Mert
fb641c74be fix(server): use preview image when generating person thumbnail from video (#10240) 2024-06-12 22:16:26 -04:00
Alex
c642150b85 chore(mobile): post release task (#10228) 2024-06-12 14:17:58 -05:00
Alex The Bot
a8a7d29891 Version v1.106.3 2024-06-12 18:26:10 +00:00
Alex
67e98ed313 fix(mobile): video player not updating state (#10220)
* fix(mobile): video player not updating state

* unused code
2024-06-12 12:43:01 -05:00
renovate[bot]
47ef48e3c2 chore(deps): update base-image to v20240611 (major) (#10118)
chore(deps): update base-image to v20240611

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-12 12:51:46 -04:00
waclaw66
376feadb76 fix(web): missing svelte translations (#10199)
* fix(web): missing svelte translations

* fixes

* format fix

* translation keys fix

* "merge" key fix

* Update web/src/lib/components/shared-components/side-bar/more-information-albums.svelte

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>

* Update web/src/lib/i18n/en.json

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>

* suggestion fix

* trash pluralization

* video+photo count fix

* format fix

* unused removal

* translation key fix

* duplicate key removal

* format fix

---------

Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
2024-06-12 17:37:46 +01:00
Jason Rasmussen
3d82005797 fix: no floats (replace with doubles) (#10218)
* fix: no floats (replace with doubles)

* Update server/src/utils/misc.ts

Co-authored-by: Zack Pollard <zackpollard@ymail.com>

---------

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2024-06-12 17:36:24 +01:00
Weblate (bot)
10aa00af21 chore(web): update translations (#10216)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/cs/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pl/
Translation: Immich/immich

Co-authored-by: Mario <17320863+myanesp@users.noreply.github.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: opl- <jakub.trzy@op.pl>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
2024-06-12 17:35:04 +01:00
Zack Pollard
1f8bdcdce7 chore: renovate shouldn't update mobile native dependencies (#10217) 2024-06-12 17:00:54 +01:00
Jason Rasmussen
98ebfc22f8 chore: translations from mobile (#10214) 2024-06-12 15:47:51 +01:00
Weblate (bot)
032b99fe93 chore(web): update translations (#10203)
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/en_devel/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/es/
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/hu/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/it/
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/ro/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ru/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/uk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_SIMPLIFIED/
Translation: Immich/immich

Co-authored-by: Alexandr Zhytnyk <oper.kh@gmail.com>
Co-authored-by: Amadeous <am4d3ous@users.noreply.hosted.weblate.org>
Co-authored-by: Beniamin Iorga <beniiorga@gmail.com>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Fanfouer <fanfouer@outlook.com>
Co-authored-by: Jan <jan.widmer.ch@gmail.com>
Co-authored-by: Kentai Radiquum <kentai.waah@gmail.com>
Co-authored-by: Kim <shnukoms@users.noreply.hosted.weblate.org>
Co-authored-by: Maximilian Waidelich <44324946+maxwai@users.noreply.github.com>
Co-authored-by: Maximilian Waidelich <maximilian.waidelich@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: PolarisYHNL <polarisyhnl@yeah.net>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Thomas <thomas.ceccato.02@gmail.com>
Co-authored-by: Yves ANDOLFATTO <register@yves.aleeas.com>
Co-authored-by: ZtereoHYPE <me@ztereohype.dev>
Co-authored-by: carcawey <dacarva@gmail.com>
Co-authored-by: clementdelestre <clementdelestre@gmail.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: mgabor <mgabor@users.noreply.hosted.weblate.org>
Co-authored-by: opl- <jakub.trzy@op.pl>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: wariw <wariwpl@gmail.com>
Co-authored-by: Владислав Потаенко <vipotaenko02@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
2024-06-12 15:38:18 +01:00
Zack Pollard
07156135c2 fix(server): double counting cores when processor name includes the word "processor" (#10211) 2024-06-12 13:49:20 +00:00
Michel Heusschen
9dbf5db72e fix(server): checkExistingAssets (#10192)
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2024-06-12 08:48:44 -05:00
Daniel Heppner
52170423be feat(web): select all duplicates (#10189)
* feat(web): select all duplicates

Allows users to select or deselect all duplicate photos when removing duplicates

* styling

* chore(web): add more translations to duplicates page

* color

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2024-06-12 13:01:55 +00:00
Zack Pollard
ae095baad3 fix(server): only run healthchecks when api worker is running on immich-server (#10204)
fix: only run healthchecks when api worker is running on immich-server
2024-06-12 12:44:30 +01:00
Michel Heusschen
f99f289f74 fix(web): small translation issues + remove unused (#10200)
* fix(web): small translation issues + remove unused

* more unused keys

* formatting

* fix(web): incorrectly used translations

* fix and remove unused translations

---------

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2024-06-12 12:13:10 +01:00
Alex
476eea44df chore(web): remove thumbnail usage for places card (#10142)
* chore(web): remove thumbnail usage for places

* remove href attribute from Thumbnail

* linting
2024-06-12 11:12:58 +00:00
Jason Rasmussen
e84657192c refactor: config caching (#10168) 2024-06-12 11:07:35 +00:00
Mert
5dda5d93f5 chore(docs): remove microservices from hwa docs (#10188)
remove microservices from hwa docs
2024-06-12 11:57:40 +01:00
Michel Heusschen
6260caf649 fix(web): multi file upload in albums (#10190) 2024-06-12 11:57:11 +01:00
Michel Heusschen
9e5c52b7b7 chore(web): more translations for user settings and admin pages (#10161)
* chore(web): more translations for user settings and admin pages

* JobSettings translations

* feedback

* missed one

* feedback
2024-06-12 11:54:40 +01:00
Weblate (bot)
0e1311e3d3 chore(web): update translations (#10152)
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/es/
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/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/ko/
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/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/sv/
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: 94tiger <94tiger@naver.com>
Co-authored-by: Adrian <adrian.hundseth@gmail.com>
Co-authored-by: Andrej Kralj <andrej.kralj@gmail.com>
Co-authored-by: AngelaDMerkel <personal@caduffy.com>
Co-authored-by: Anton <ajp_anton@hotmail.com>
Co-authored-by: Beniamin Iorga <beniiorga@gmail.com>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Eero Jääskeläinen <eero.jaaskelainen@gmail.com>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Flowake <weblate.cx6on@passmail.net>
Co-authored-by: Immich <immich@futo.org>
Co-authored-by: Jakub <jakubula.jm@gmail.com>
Co-authored-by: Jan <account@thebraker.net>
Co-authored-by: Jan <jan.widmer.ch@gmail.com>
Co-authored-by: Jason Dean Lessenich <jasonlessenich@gmail.com>
Co-authored-by: Joachim Klahr <joachim@klahr.se>
Co-authored-by: Joseph <josephlegrand33+hosted.weblate.org@gmail.com>
Co-authored-by: Julien Deveaux <julien.deveaux@hotmail.com>
Co-authored-by: Kentai Radiquum <kentai.waah@gmail.com>
Co-authored-by: Kim <shnukoms@users.noreply.hosted.weblate.org>
Co-authored-by: Kyle Park <mysky3056@gmail.com>
Co-authored-by: League2EB <info@league2eb.me>
Co-authored-by: Londoneye02 <jcdelcaz@gmail.com>
Co-authored-by: Luca Kröger <l.kroeger01@gmail.com>
Co-authored-by: Manic87 <nicolas@familie-mach.net>
Co-authored-by: Marcos Besteiro López (MarcosBL) <marcosbl@gmail.com>
Co-authored-by: MeisterEder286 <walbrun.johann@gmail.com>
Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
Co-authored-by: Miko-Matias Grönvall <matias.gronvall@gmail.com>
Co-authored-by: MozPri <primoz.arh@gmail.com>
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
Co-authored-by: Ole Morten Didriksen <code@oledid.com>
Co-authored-by: Pavel Shamshin <odan@selaz.org>
Co-authored-by: Peter Suba <peter.suba@gmail.com>
Co-authored-by: Pheggas <petko252@gmail.com>
Co-authored-by: PolarisYHNL <polarisyhnl@yeah.net>
Co-authored-by: Ptsa Daniel <ptsa1987@gmail.com>
Co-authored-by: RWDai <869759838@qq.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Simmer Lajos <weblate.linguini033@passinbox.com>
Co-authored-by: SisyphusMD <guardian.note2892@fastmail.com>
Co-authored-by: Smiehoo <github@pocz.net>
Co-authored-by: Thomas <thomas.ceccato.02@gmail.com>
Co-authored-by: Tomas Babej <web+weblate@tbabej.com>
Co-authored-by: Tomek <tjomek@gmail.com>
Co-authored-by: VB <Victor2B@protonmail.com>
Co-authored-by: Vojtěch Bargl <bargl.vojtech@gmail.com>
Co-authored-by: YFrendo <yann.frendo@live.fr>
Co-authored-by: Yves ANDOLFATTO <register@yves.aleeas.com>
Co-authored-by: ZtereoHYPE <me@ztereohype.dev>
Co-authored-by: biglate <bigtech+weblate@aleeas.com>
Co-authored-by: carcawey <dacarva@gmail.com>
Co-authored-by: clementdelestre <clementdelestre@gmail.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: ferrets <ferrets@live.cn>
Co-authored-by: frauhottelmann <frauhottelmann@gmail.com>
Co-authored-by: gilo <giantlolli@proton.me>
Co-authored-by: grgergo <gergo_g@proton.me>
Co-authored-by: guillezcurra <guillezcurra@gmail.com>
Co-authored-by: ingria <codefuhrer@gmail.com>
Co-authored-by: jie65535 <jie65535@qq.com>
Co-authored-by: myurar1a <sirometroid1235@outlook.jp>
Co-authored-by: sephrat <florian.dupret@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
Co-authored-by: Кирилл Москатов <kirillmoskatov@gmail.com>
2024-06-12 11:52:33 +01:00
Stephen Smith
216cca4383 fix(server): exiftool largefilesupport only set for the first call (#10167)
* Revert "feat(server): enable exiftool largefilesupport (#9894)"

This reverts commit afa10ebcb2.

* feat(server): enable exiftool largefilesupport by passing options to read
2024-06-12 05:43:38 -05:00
Mert
cdc98de848 fix(server): increase pixel limit for thumbnail generation (#10181)
disable input limit
2024-06-11 22:11:03 -04:00
Mert
126cbeabe8 feat(server): add av1 support for vaapi (#10180)
add av1
2024-06-12 00:24:06 +00:00
Mert
2e0c6f6fff fix: postgres health check reporting any db without checksums as unhealthy (#10178)
handle disabled checksumming
2024-06-12 00:18:24 +00:00
1033 changed files with 91214 additions and 44014 deletions

View File

@@ -29,3 +29,4 @@ web/node_modules/
web/coverage/
web/.svelte-kit
web/build/
web/.env

View File

@@ -1,11 +1,13 @@
title: "[Feature] <feature-name-goes-here>"
title: "[Feature] feature-name-goes-here"
labels: ["feature"]
body:
- type: markdown
attributes:
value: |
Please use this form to request new feature for Immich
Please use this form to request new feature for Immich.
Stick to only a single feature per request. If you list multiple different features at once,
your request will be closed.
- type: checkboxes
attributes:

View File

@@ -1,11 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: I have a question or need support
url: https://discord.gg/D8JsnBEuKb
url: https://discord.immich.app
about: We use GitHub for tracking bugs, please check out our Discord channel for freaky fast support.
- name: Feature Request
url: https://github.com/immich-app/immich/discussions/new?category=feature-request
about: Please use our GitHub Discussion for making feature requests.
- name: I'm unsure where to go
url: https://discord.gg/D8JsnBEuKb
url: https://discord.immich.app
about: If you are unsure where to go, then joining our Discord is recommended; Just ask!

36
.github/labeler.yml vendored
View File

@@ -1,23 +1,35 @@
cli:
- changed-files:
- any-glob-to-any-file: cli/**
- changed-files:
- any-glob-to-any-file:
- cli/src/**
documentation:
- changed-files:
- any-glob-to-any-file: docs/**
- changed-files:
- any-glob-to-any-file:
- docs/blob/**
- docs/docs/**
- docs/src/**
- docs/static/**
🖥web:
- changed-files:
- any-glob-to-any-file: web/**
- changed-files:
- any-glob-to-any-file:
- web/src/**
- web/static/**
📱mobile:
- changed-files:
- any-glob-to-any-file: mobile/**
- changed-files:
- any-glob-to-any-file:
- mobile/lib/**
- mobile/test/**
🗄server:
- changed-files:
- any-glob-to-any-file: server/**
- changed-files:
- any-glob-to-any-file:
- server/src/**
- server/test/**
🧠machine-learning:
- changed-files:
- any-glob-to-any-file: machine-learning/**
- changed-files:
- any-glob-to-any-file:
- machine-learning/app/**

36
.github/release.yml vendored
View File

@@ -1,41 +1,29 @@
changelog:
categories:
- title: ⚠️ Breaking Changes
- title: 🚨 Breaking Changes
labels:
- breaking-change
- title: 🗄️ Server
- title: 🔒 Security
labels:
- 🗄server
- security
- title: 📱 Mobile
- title: 🚀 Features
labels:
- 📱mobile
- feature
- title: 🖥️ Web
- title: 🌟 Enhancements
labels:
- 🖥web
- enhancement
- title: 🧠 Machine Learning
- title: 🐛 Bug fixes
labels:
- 🧠machine-learning
- bugfix
- title: ⚡ CLI
labels:
- cli
- title: 📓 Documentation
- title: 📚 Documentation
labels:
- documentation
- title: 🔨 Maintenance
- title: 🌐 Translations
labels:
- deployment
- dependencies
- renovate
- maintenance
- tech-debt
- title: Other changes
labels:
- "*"
- translation

View File

@@ -33,7 +33,7 @@ jobs:
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4
with:
node-version: '20.x'
node-version-file: './cli/.nvmrc'
registry-url: 'https://registry.npmjs.org'
- name: Prepare SDK
run: npm ci --prefix ../open-api/typescript-sdk/
@@ -56,10 +56,10 @@ jobs:
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.0.0
uses: docker/setup-qemu-action@v3.2.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.3.0
uses: docker/setup-buildx-action@v3.6.1
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
@@ -88,7 +88,7 @@ jobs:
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
- name: Build and push image
uses: docker/build-push-action@v5.4.0
uses: docker/build-push-action@v6.6.1
with:
file: cli/Dockerfile
platforms: linux/amd64,linux/arm64

View File

@@ -35,7 +35,7 @@ jobs:
steps:
- name: Clean temporary images
if: "${{ env.TOKEN != '' }}"
uses: stumpylog/image-cleaner-action/ephemeral@v0.7.0
uses: stumpylog/image-cleaner-action/ephemeral@v0.8.0
with:
token: "${{ env.TOKEN }}"
owner: "immich-app"
@@ -64,7 +64,7 @@ jobs:
steps:
- name: Clean untagged images
if: "${{ env.TOKEN != '' }}"
uses: stumpylog/image-cleaner-action/untagged@v0.7.0
uses: stumpylog/image-cleaner-action/untagged@v0.8.0
with:
token: "${{ env.TOKEN }}"
owner: "immich-app"

View File

@@ -63,10 +63,10 @@ jobs:
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.0.0
uses: docker/setup-qemu-action@v3.2.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.3.0
uses: docker/setup-buildx-action@v3.6.1
- name: Login to Docker Hub
# Only push to Docker Hub when making a release
@@ -115,7 +115,7 @@ jobs:
fi
- name: Build and push image
uses: docker/build-push-action@v5.4.0
uses: docker/build-push-action@v6.6.1
with:
context: ${{ matrix.context }}
file: ${{ matrix.file }}
@@ -124,7 +124,11 @@ jobs:
push: ${{ !github.event.pull_request.head.repo.fork }}
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{matrix.image}}
cache-to: ${{ steps.cache-target.outputs.cache-to }}
build-args: |
DEVICE=${{ matrix.device }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
build-args: |
DEVICE=${{ matrix.device }}
BUILD_ID=${{ github.run_id }}
BUILD_IMAGE=${{ github.event_name == 'release' && github.ref_name || steps.metadata.outputs.tags }}
BUILD_SOURCE_REF=${{ github.ref_name }}
BUILD_SOURCE_COMMIT=${{ github.sha }}

View File

@@ -26,6 +26,11 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: './docs/.nvmrc'
- name: Run npm install
run: npm ci

View File

@@ -19,7 +19,7 @@ jobs:
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4
with:
node-version: '20.x'
node-version-file: './open-api/typescript-sdk/.nvmrc'
registry-url: 'https://registry.npmjs.org'
- name: Install deps
run: npm ci

View File

@@ -21,6 +21,11 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: './server/.nvmrc'
- name: Run npm install
run: npm ci
@@ -54,7 +59,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version-file: './cli/.nvmrc'
- name: Setup typescript-sdk
run: npm ci && npm run build
@@ -79,6 +84,38 @@ jobs:
run: npm run test:cov
if: ${{ !cancelled() }}
cli-unit-tests-win:
name: CLI (Windows)
runs-on: windows-latest
defaults:
run:
working-directory: ./cli
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: './cli/.nvmrc'
- name: Setup typescript-sdk
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
- name: Install deps
run: npm ci
# Skip linter & formatter in Windows test.
- name: Run tsc
run: npm run check
if: ${{ !cancelled() }}
- name: Run unit tests & coverage
run: npm run test:cov
if: ${{ !cancelled() }}
web-unit-tests:
name: Web
runs-on: ubuntu-latest
@@ -90,6 +127,11 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: './web/.nvmrc'
- name: Run setup typescript-sdk
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
@@ -133,7 +175,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version-file: './e2e/.nvmrc'
- name: Run setup typescript-sdk
run: npm ci && npm run build
@@ -241,6 +283,11 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: './server/.nvmrc'
- name: Install server dependencies
run: npm --prefix=server ci
@@ -291,6 +338,11 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: './server/.nvmrc'
- name: Install server dependencies
run: npm ci

View File

@@ -131,4 +131,4 @@ conduct enforcement ladder](https://github.com/mozilla/diversity).
For answers to common questions about this code of conduct, see the
FAQ at https://www.contributor-covenant.org/faq. Translations are
available at https://www.contributor-covenant.org/translations.
available at https://www.contributor-covenant.org/translations.

View File

@@ -35,3 +35,51 @@ sql:
attach-server:
docker exec -it docker_immich-server_1 sh
renovate:
LOG_LEVEL=debug npx renovate --platform=local --repository-cache=reset
MODULES = e2e server web cli sdk
audit-%:
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
install-%:
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
build-cli: build-sdk
build-web: build-sdk
build-%: install-%
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'build' >/dev/null \
&& npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run build || true
format-%:
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'format:fix' >/dev/null \
&& npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run format:fix || true
lint-%:
npm --prefix $* run lint:fix
check-%:
npm --prefix $* run check
check-web:
npm --prefix web run check:typescript
npm --prefix web run check:svelte
test-%:
npm --prefix $* run test
test-e2e:
docker compose -f ./e2e/docker-compose.yml build
npm --prefix e2e run test
npm --prefix e2e run test:web
build-all: $(foreach M,$(MODULES),build-$M) ;
install-all: $(foreach M,$(MODULES),install-$M) ;
check-all: $(foreach M,$(MODULES),check-$M) ;
lint-all: $(foreach M,$(MODULES),lint-$M) ;
format-all: $(foreach M,$(MODULES),format-$M) ;
audit-all: $(foreach M,$(MODULES),audit-$M) ;
hygiene-all: lint-all format-all check-all sql audit-all;
test-all: $(foreach M,$(MODULES),test-$M) ;
clean:
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
find . -name "dist" -type d -prune -exec rm -rf '{}' +
find . -name "build" -type d -prune -exec rm -rf '{}' +
find . -name "svelte-kit" -type d -prune -exec rm -rf '{}' +
docker compose -f ./docker/docker-compose.dev.yml rm -v -f || true
docker compose -f ./e2e/docker-compose.yml rm -v -f || true

View File

@@ -1,7 +1,7 @@
<p align="center">
<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://discord.gg/D8JsnBEuKb">
<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"/>
</a>
<br/>
@@ -19,20 +19,21 @@
<br/>
<p align="center">
<a href="readme_i18n/README_ca_ES.md">Català</a>
<a href="readme_i18n/README_es_ES.md">Español</a>
<a href="readme_i18n/README_fr_FR.md">Français</a>
<a href="readme_i18n/README_it_IT.md">Italiano</a>
<a href="readme_i18n/README_ja_JP.md">日本語</a>
<a href="readme_i18n/README_ko_KR.md">한국어</a>
<a href="readme_i18n/README_de_DE.md">Deutsch</a>
<a href="readme_i18n/README_nl_NL.md">Nederlands</a>
<a href="readme_i18n/README_tr_TR.md">Türkçe</a>
<a href="readme_i18n/README_zh_CN.md">中文</a>
<a href="readme_i18n/README_ru_RU.md">Русский</a>
<a href="readme_i18n/README_pt_BR.md">Português Brasileiro</a>
<a href="readme_i18n/README_sv_SE.md">Svenska</a>
<a href="readme_i18n/README_ar_JO.md">العربية</a>
<a href="readme_i18n/README_ca_ES.md">Català</a>
<a href="readme_i18n/README_es_ES.md">Español</a>
<a href="readme_i18n/README_fr_FR.md">Français</a>
<a href="readme_i18n/README_it_IT.md">Italiano</a>
<a href="readme_i18n/README_ja_JP.md">日本語</a>
<a href="readme_i18n/README_ko_KR.md">한국어</a>
<a href="readme_i18n/README_de_DE.md">Deutsch</a>
<a href="readme_i18n/README_nl_NL.md">Nederlands</a>
<a href="readme_i18n/README_tr_TR.md">Türkçe</a>
<a href="readme_i18n/README_zh_CN.md">中文</a>
<a href="readme_i18n/README_ru_RU.md">Русский</a>
<a href="readme_i18n/README_pt_BR.md">Português Brasileiro</a>
<a href="readme_i18n/README_sv_SE.md">Svenska</a>
<a href="readme_i18n/README_ar_JO.md">العربية</a>
</p>
## Disclaimer
@@ -42,45 +43,36 @@
- ⚠️ **Do not use the app as the only way to store your photos and videos.**
- ⚠️ Always follow [3-2-1](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/) backup plan for your precious photos and videos!
## Content
> [!NOTE]
> You can find the main documentation, including installation guides, at https://immich.app/.
- [Official Documentation](https://immich.app/docs)
- [Roadmap](https://github.com/orgs/immich-app/projects/1)
## Links
- [Documentation](https://immich.app/docs)
- [About](https://immich.app/docs/overview/introduction)
- [Installation](https://immich.app/docs/install/requirements)
- [Roadmap](https://immich.app/roadmap)
- [Demo](#demo)
- [Features](#features)
- [Introduction](https://immich.app/docs/overview/introduction)
- [Installation](https://immich.app/docs/install/requirements)
- [Contribution Guidelines](https://immich.app/docs/overview/support-the-project)
## Documentation
You can find the main documentation, including installation guides, at https://immich.app/.
- [Translations](https://immich.app/docs/developer/translations)
- [Contributing](https://immich.app/docs/overview/support-the-project)
## Demo
You can access the web demo at https://demo.immich.app
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.
For the mobile app, you can use `https://demo.immich.app/api` for the `Server Endpoint URL`
```bash title="Demo Credential"
The credential
email: demo@immich.app
password: demo
```
### Login credentials
```
Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM
```
## Activities
![Activities](https://repobeats.axiom.co/api/embed/9e86d9dc3ddd137161f2f6d2e758d7863b1789cb.svg "Repobeats analytics image")
| Email | Password |
| --------------- | -------- |
| demo@immich.app | demo |
## Features
| Features | Mobile | Web |
| :--------------------------------------------- | -------- | ----- |
| :------------------------------------------- | ------ | --- |
| Upload and view videos and photos | Yes | Yes |
| Auto backup when the app is opened | Yes | N/A |
| Prevent duplication of assets | Yes | Yes |
@@ -110,13 +102,19 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM
| Read-only gallery | Yes | Yes |
| Stacked Photos | Yes | Yes |
## Contributors
## Translations
<a href="https://github.com/alextran1502/immich/graphs/contributors">
<img src="https://contrib.rocks/image?repo=immich-app/immich" width="100%"/>
Read more about translations [here](https://immich.app/docs/developer/translations).
<a href="https://hosted.weblate.org/engage/immich/">
<img src="https://hosted.weblate.org/widget/immich/immich/multi-auto.svg" alt="Translation status" />
</a>
## Star History
## Repository activity
![Activities](https://repobeats.axiom.co/api/embed/9e86d9dc3ddd137161f2f6d2e758d7863b1789cb.svg "Repobeats analytics image")
## Star history
<a href="https://star-history.com/#immich-app/immich&Date">
<picture>
@@ -125,3 +123,9 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=immich-app/immich&type=Date" width="100%" />
</picture>
</a>
## Contributors
<a href="https://github.com/alextran1502/immich/graphs/contributors">
<img src="https://contrib.rocks/image?repo=immich-app/immich" width="100%"/>
</a>

View File

@@ -2,4 +2,4 @@
## Reporting a Vulnerability
Please report security issues to `alex.tran1502@gmail.com`
Please report security issues to `security@immich.app`

View File

@@ -1 +0,0 @@
/dist

View File

@@ -1,28 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'plugin:unicorn/recommended'],
root: true,
env: {
node: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/prevent-abbreviations': 'off',
'unicorn/no-process-exit': 'off',
'unicorn/import-style': 'off',
curly: 2,
'prettier/prettier': 0,
},
};

View File

@@ -1 +1 @@
20.14
20.16.0

View File

@@ -1,4 +1,4 @@
FROM node:20-alpine3.19@sha256:696ae41fb5880949a15ade7879a2deae93b3f0723f757bdb5b8a9e4a744ce27f as core
FROM node:20.16.0-alpine3.20@sha256:eb8101caae9ac02229bd64c024919fe3d4504ff7f329da79ca60a04db08cef52 AS core
WORKDIR /usr/src/open-api/typescript-sdk
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
@@ -16,4 +16,4 @@ RUN npm run build
WORKDIR /import
ENTRYPOINT ["node", "/usr/src/app/dist"]
ENTRYPOINT ["node", "/usr/src/app/dist"]

60
cli/eslint.config.mjs Normal file
View File

@@ -0,0 +1,60 @@
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import globals from 'globals';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
{
ignores: ['eslint.config.mjs', 'dist'],
},
...compat.extends(
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'plugin:unicorn/recommended',
),
{
plugins: {
'@typescript-eslint': typescriptEslint,
},
languageOptions: {
globals: {
...globals.node,
},
parser: tsParser,
ecmaVersion: 5,
sourceType: 'module',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
},
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/prevent-abbreviations': 'off',
'unicorn/no-process-exit': 'off',
'unicorn/import-style': 'off',
curly: 2,
'prettier/prettier': 0,
},
},
];

1878
cli/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@immich/cli",
"version": "2.2.2",
"version": "2.2.14",
"description": "Command Line Interface (CLI) for Immich",
"type": "module",
"exports": "./dist/index.js",
@@ -13,29 +13,33 @@
"cli"
],
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@types/byte-size": "^8.1.0",
"@types/cli-progress": "^3.11.0",
"@types/lodash-es": "^4.17.12",
"@types/mock-fs": "^4.13.1",
"@types/node": "^20.3.1",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0",
"@vitest/coverage-v8": "^1.2.2",
"byte-size": "^8.1.1",
"@types/node": "^20.14.14",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"@vitest/coverage-v8": "^2.0.5",
"byte-size": "^9.0.0",
"cli-progress": "^3.12.0",
"commander": "^12.0.0",
"eslint": "^8.56.0",
"eslint": "^9.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^53.0.0",
"eslint-plugin-unicorn": "^55.0.0",
"globals": "^15.9.0",
"mock-fs": "^5.2.0",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-organize-imports": "^4.0.0",
"typescript": "^5.3.3",
"vite": "^5.0.12",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.2.2",
"vite-tsconfig-paths": "^5.0.0",
"vitest": "^2.0.5",
"vitest-fetch-mock": "^0.3.0",
"yaml": "^2.3.1"
},
"scripts": {
@@ -59,9 +63,10 @@
},
"dependencies": {
"fast-glob": "^3.3.2",
"fastq": "^1.17.1",
"lodash-es": "^4.17.21"
},
"volta": {
"node": "20.14.0"
"node": "20.16.0"
}
}

View File

@@ -0,0 +1,201 @@
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { describe, expect, it, vi } from 'vitest';
import { Action, checkBulkUpload, defaults, Reason } from '@immich/sdk';
import createFetchMock from 'vitest-fetch-mock';
import { checkForDuplicates, getAlbumName, uploadFiles, UploadOptionsDto } from './asset';
vi.mock('@immich/sdk');
describe('getAlbumName', () => {
it('should return a non-undefined value', () => {
if (os.platform() === 'win32') {
// This is meaningless for Unix systems.
expect(getAlbumName(String.raw`D:\test\Filename.txt`, {} as UploadOptionsDto)).toBe('test');
}
expect(getAlbumName('D:/parentfolder/test/Filename.txt', {} as UploadOptionsDto)).toBe('test');
});
it('has higher priority to return `albumName` in `options`', () => {
expect(getAlbumName('/parentfolder/test/Filename.txt', { albumName: 'example' } as UploadOptionsDto)).toBe(
'example',
);
});
});
describe('uploadFiles', () => {
const testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
const testFilePath = path.join(testDir, 'test.png');
const testFileData = 'test';
const baseUrl = 'http://example.com';
const apiKey = 'key';
const retry = 3;
const fetchMocker = createFetchMock(vi);
beforeEach(() => {
// Create a test file
fs.writeFileSync(testFilePath, testFileData);
// Defaults
vi.mocked(defaults).baseUrl = baseUrl;
vi.mocked(defaults).headers = { 'x-api-key': apiKey };
fetchMocker.enableMocks();
fetchMocker.resetMocks();
});
it('returns new assets when upload file is successful', async () => {
fetchMocker.doMockIf(new RegExp(`${baseUrl}/assets$`), () => {
return {
status: 200,
body: JSON.stringify({ id: 'fc5621b1-86f6-44a1-9905-403e607df9f5', status: 'created' }),
};
});
await expect(uploadFiles([testFilePath], { concurrency: 1 })).resolves.toEqual([
{
filepath: testFilePath,
id: 'fc5621b1-86f6-44a1-9905-403e607df9f5',
},
]);
});
it('returns new assets when upload file retry is successful', async () => {
let counter = 0;
fetchMocker.doMockIf(new RegExp(`${baseUrl}/assets$`), () => {
counter++;
if (counter < retry) {
throw new Error('Network error');
}
return {
status: 200,
body: JSON.stringify({ id: 'fc5621b1-86f6-44a1-9905-403e607df9f5', status: 'created' }),
};
});
await expect(uploadFiles([testFilePath], { concurrency: 1 })).resolves.toEqual([
{
filepath: testFilePath,
id: 'fc5621b1-86f6-44a1-9905-403e607df9f5',
},
]);
});
it('returns new assets when upload file retry is failed', async () => {
fetchMocker.doMockIf(new RegExp(`${baseUrl}/assets$`), () => {
throw new Error('Network error');
});
await expect(uploadFiles([testFilePath], { concurrency: 1 })).resolves.toEqual([]);
});
});
describe('checkForDuplicates', () => {
const testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
const testFilePath = path.join(testDir, 'test.png');
const testFileData = 'test';
const testFileChecksum = 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'; // SHA1
const retry = 3;
beforeEach(() => {
// Create a test file
fs.writeFileSync(testFilePath, testFileData);
});
it('checks duplicates', async () => {
vi.mocked(checkBulkUpload).mockResolvedValue({
results: [
{
action: Action.Accept,
id: testFilePath,
},
],
});
await checkForDuplicates([testFilePath], { concurrency: 1 });
expect(checkBulkUpload).toHaveBeenCalledWith({
assetBulkUploadCheckDto: {
assets: [
{
checksum: testFileChecksum,
id: testFilePath,
},
],
},
});
});
it('returns duplicates when check duplicates is rejected', async () => {
vi.mocked(checkBulkUpload).mockResolvedValue({
results: [
{
action: Action.Reject,
id: testFilePath,
assetId: 'fc5621b1-86f6-44a1-9905-403e607df9f5',
reason: Reason.Duplicate,
},
],
});
await expect(checkForDuplicates([testFilePath], { concurrency: 1 })).resolves.toEqual({
duplicates: [
{
filepath: testFilePath,
id: 'fc5621b1-86f6-44a1-9905-403e607df9f5',
},
],
newFiles: [],
});
});
it('returns new assets when check duplicates is accepted', async () => {
vi.mocked(checkBulkUpload).mockResolvedValue({
results: [
{
action: Action.Accept,
id: testFilePath,
},
],
});
await expect(checkForDuplicates([testFilePath], { concurrency: 1 })).resolves.toEqual({
duplicates: [],
newFiles: [testFilePath],
});
});
it('returns results when check duplicates retry is successful', async () => {
let mocked = vi.mocked(checkBulkUpload);
for (let i = 1; i < retry; i++) {
mocked = mocked.mockRejectedValueOnce(new Error('Network error'));
}
mocked.mockResolvedValue({
results: [
{
action: Action.Accept,
id: testFilePath,
},
],
});
await expect(checkForDuplicates([testFilePath], { concurrency: 1 })).resolves.toEqual({
duplicates: [],
newFiles: [testFilePath],
});
});
it('returns results when check duplicates retry is failed', async () => {
vi.mocked(checkBulkUpload).mockRejectedValue(new Error('Network error'));
await expect(checkForDuplicates([testFilePath], { concurrency: 1 })).resolves.toEqual({
duplicates: [],
newFiles: [],
});
});
});

View File

@@ -15,8 +15,8 @@ import { Presets, SingleBar } from 'cli-progress';
import { chunk } from 'lodash-es';
import { Stats, createReadStream } from 'node:fs';
import { stat, unlink } from 'node:fs/promises';
import os from 'node:os';
import path, { basename } from 'node:path';
import { Queue } from 'src/queue';
import { BaseOptions, authenticate, crawl, sha1 } from 'src/utils';
const s = (count: number) => (count === 1 ? '' : 's');
@@ -25,7 +25,7 @@ const s = (count: number) => (count === 1 ? '' : 's');
type AssetBulkUploadCheckResults = Array<AssetBulkUploadCheckResult & { id: string }>;
type Asset = { id: string; filepath: string };
interface UploadOptionsDto {
export interface UploadOptionsDto {
recursive?: boolean;
ignore?: string;
dryRun?: boolean;
@@ -84,7 +84,7 @@ const scan = async (pathsToCrawl: string[], options: UploadOptionsDto) => {
return files;
};
const checkForDuplicates = async (files: string[], { concurrency, skipHash }: UploadOptionsDto) => {
export const checkForDuplicates = async (files: string[], { concurrency, skipHash }: UploadOptionsDto) => {
if (skipHash) {
console.log('Skipping hash check, assuming all files are new');
return { newFiles: files, duplicates: [] };
@@ -100,32 +100,50 @@ const checkForDuplicates = async (files: string[], { concurrency, skipHash }: Up
const newFiles: string[] = [];
const duplicates: Asset[] = [];
try {
// TODO refactor into a queue
for (const items of chunk(files, concurrency)) {
const dto = await Promise.all(items.map(async (filepath) => ({ id: filepath, checksum: await sha1(filepath) })));
const { results } = await checkBulkUpload({ assetBulkUploadCheckDto: { assets: dto } });
for (const { id: filepath, assetId, action } of results as AssetBulkUploadCheckResults) {
const queue = new Queue<string[], AssetBulkUploadCheckResults>(
async (filepaths: string[]) => {
const dto = await Promise.all(
filepaths.map(async (filepath) => ({ id: filepath, checksum: await sha1(filepath) })),
);
const response = await checkBulkUpload({ assetBulkUploadCheckDto: { assets: dto } });
const results = response.results as AssetBulkUploadCheckResults;
for (const { id: filepath, assetId, action } of results) {
if (action === Action.Accept) {
newFiles.push(filepath);
} else {
// rejects are always duplicates
duplicates.push({ id: assetId as string, filepath });
}
progressBar.increment();
}
}
} finally {
progressBar.stop();
progressBar.increment(filepaths.length);
return results;
},
{ concurrency, retry: 3 },
);
for (const items of chunk(files, concurrency)) {
await queue.push(items);
}
await queue.drained();
progressBar.stop();
console.log(`Found ${newFiles.length} new files and ${duplicates.length} duplicate${s(duplicates.length)}`);
// Report failures
const failedTasks = queue.tasks.filter((task) => task.status === 'failed');
if (failedTasks.length > 0) {
console.log(`Failed to verify ${failedTasks.length} file${s(failedTasks.length)}:`);
for (const task of failedTasks) {
console.log(`- ${task.data} - ${task.error}`);
}
}
return { newFiles, duplicates };
};
const uploadFiles = async (files: string[], { dryRun, concurrency }: UploadOptionsDto): Promise<Asset[]> => {
export const uploadFiles = async (files: string[], { dryRun, concurrency }: UploadOptionsDto): Promise<Asset[]> => {
if (files.length === 0) {
console.log('All assets were already uploaded, nothing to do.');
return [];
@@ -159,37 +177,52 @@ const uploadFiles = async (files: string[], { dryRun, concurrency }: UploadOptio
const newAssets: Asset[] = [];
try {
for (const items of chunk(files, concurrency)) {
await Promise.all(
items.map(async (filepath) => {
const stats = statsMap.get(filepath) as Stats;
const response = await uploadFile(filepath, stats);
const queue = new Queue<string, AssetMediaResponseDto>(
async (filepath: string) => {
const stats = statsMap.get(filepath);
if (!stats) {
throw new Error(`Stats not found for ${filepath}`);
}
newAssets.push({ id: response.id, filepath });
const response = await uploadFile(filepath, stats);
newAssets.push({ id: response.id, filepath });
if (response.status === AssetMediaStatus.Duplicate) {
duplicateCount++;
duplicateSize += stats.size ?? 0;
} else {
successCount++;
successSize += stats.size ?? 0;
}
if (response.status === AssetMediaStatus.Duplicate) {
duplicateCount++;
duplicateSize += stats.size ?? 0;
} else {
successCount++;
successSize += stats.size ?? 0;
}
uploadProgress.update(successSize, { value_formatted: byteSize(successSize + duplicateSize) });
uploadProgress.update(successSize, { value_formatted: byteSize(successSize + duplicateSize) });
return response;
},
{ concurrency, retry: 3 },
);
return response;
}),
);
}
} finally {
uploadProgress.stop();
for (const filepath of files) {
await queue.push(filepath);
}
await queue.drained();
uploadProgress.stop();
console.log(`Successfully uploaded ${successCount} new asset${s(successCount)} (${byteSize(successSize)})`);
if (duplicateCount > 0) {
console.log(`Skipped ${duplicateCount} duplicate asset${s(duplicateCount)} (${byteSize(duplicateSize)})`);
}
// Report failures
const failedTasks = queue.tasks.filter((task) => task.status === 'failed');
if (failedTasks.length > 0) {
console.log(`Failed to upload ${failedTasks.length} asset${s(failedTasks.length)}:`);
for (const task of failedTasks) {
console.log(`- ${task.data} - ${task.error}`);
}
}
return newAssets;
};
@@ -346,7 +379,9 @@ const updateAlbums = async (assets: Asset[], options: UploadOptionsDto) => {
}
};
const getAlbumName = (filepath: string, options: UploadOptionsDto) => {
const folderName = os.platform() === 'win32' ? filepath.split('\\').at(-2) : filepath.split('/').at(-2);
return options.albumName ?? folderName;
// `filepath` valid format:
// - Windows: `D:\\test\\Filename.txt` or `D:/test/Filename.txt`
// - Unix: `/test/Filename.txt`
export const getAlbumName = (filepath: string, options: UploadOptionsDto) => {
return options.albumName ?? path.basename(path.dirname(filepath));
};

131
cli/src/queue.ts Normal file
View File

@@ -0,0 +1,131 @@
import * as fastq from 'fastq';
import { uniqueId } from 'lodash-es';
export type Task<T, R> = {
readonly id: string;
status: 'idle' | 'processing' | 'succeeded' | 'failed';
data: T;
error: unknown | undefined;
count: number;
// TODO: Could be useful to adding progress property.
// TODO: Could be useful to adding start_at/end_at/duration properties.
result: undefined | R;
};
export type QueueOptions = {
verbose?: boolean;
concurrency?: number;
retry?: number;
// TODO: Could be useful to adding timeout property for retry.
};
export type ComputedQueueOptions = Required<QueueOptions>;
export const defaultQueueOptions = {
concurrency: 1,
retry: 0,
verbose: false,
};
/**
* An in-memory queue that processes tasks in parallel with a given concurrency.
* @see {@link https://www.npmjs.com/package/fastq}
* @template T - The type of the worker task data.
* @template R - The type of the worker output data.
*/
export class Queue<T, R> {
private readonly queue: fastq.queueAsPromised<string, Task<T, R>>;
private readonly store = new Map<string, Task<T, R>>();
readonly options: ComputedQueueOptions;
readonly worker: (data: T) => Promise<R>;
/**
* Create a new queue.
* @param worker - The worker function that processes the task.
* @param options - The queue options.
*/
constructor(worker: (data: T) => Promise<R>, options?: QueueOptions) {
this.options = { ...defaultQueueOptions, ...options };
this.worker = worker;
this.store = new Map<string, Task<T, R>>();
this.queue = this.buildQueue();
}
get tasks(): Task<T, R>[] {
const tasks: Task<T, R>[] = [];
for (const task of this.store.values()) {
tasks.push(task);
}
return tasks;
}
getTask(id: string): Task<T, R> {
const task = this.store.get(id);
if (!task) {
throw new Error(`Task with id ${id} not found`);
}
return task;
}
/**
* Wait for the queue to be empty.
* @returns Promise<void> - The returned Promise will be resolved when all tasks in the queue have been processed by a worker.
* This promise could be ignored as it will not lead to a `unhandledRejection`.
*/
async drained(): Promise<void> {
await this.queue.drain();
}
/**
* Add a task at the end of the queue.
* @see {@link https://www.npmjs.com/package/fastq}
* @param data
* @returns Promise<void> - A Promise that will be fulfilled (rejected) when the task is completed successfully (unsuccessfully).
* This promise could be ignored as it will not lead to a `unhandledRejection`.
*/
async push(data: T): Promise<Task<T, R>> {
const id = uniqueId();
const task: Task<T, R> = { id, status: 'idle', error: undefined, count: 0, data, result: undefined };
this.store.set(id, task);
return this.queue.push(id);
}
// TODO: Support more function delegation to fastq.
private buildQueue(): fastq.queueAsPromised<string, Task<T, R>> {
return fastq.promise((id: string) => {
const task = this.getTask(id);
return this.work(task);
}, this.options.concurrency);
}
private async work(task: Task<T, R>): Promise<Task<T, R>> {
task.count += 1;
task.error = undefined;
task.status = 'processing';
if (this.options.verbose) {
console.log('[task] processing:', task);
}
try {
task.result = await this.worker(task.data);
task.status = 'succeeded';
if (this.options.verbose) {
console.log('[task] succeeded:', task);
}
return task;
} catch (error) {
task.error = error;
task.status = 'failed';
if (this.options.verbose) {
console.log('[task] failed:', task);
}
if (this.options.retry > 0 && task.count < this.options.retry) {
if (this.options.verbose) {
console.log('[task] retry:', task);
}
return this.work(task);
}
return task;
}
}
}

View File

@@ -1,4 +1,5 @@
import mockfs from 'mock-fs';
import { readFileSync } from 'node:fs';
import { CrawlOptions, crawl } from 'src/utils';
interface Test {
@@ -9,6 +10,10 @@ interface Test {
const cwd = process.cwd();
const readContent = (path: string) => {
return readFileSync(path).toString();
};
const extensions = [
'.jpg',
'.jpeg',
@@ -256,7 +261,8 @@ const tests: Test[] = [
{
test: 'should support ignoring absolute paths',
options: {
pathsToCrawl: ['/'],
// Currently, fast-glob has some caveat when dealing with `/`.
pathsToCrawl: ['/*s'],
recursive: true,
exclusionPattern: '/images/**',
},
@@ -276,14 +282,16 @@ describe('crawl', () => {
describe('crawl', () => {
for (const { test, options, files } of tests) {
it(test, async () => {
mockfs(Object.fromEntries(Object.keys(files).map((file) => [file, ''])));
// The file contents is the same as the path.
mockfs(Object.fromEntries(Object.keys(files).map((file) => [file, file])));
const actual = await crawl({ ...options, extensions });
const expected = Object.entries(files)
.filter((entry) => entry[1])
.map(([file]) => file);
expect(actual.sort()).toEqual(expected.sort());
// Compare file's content instead of path since a file can be represent in multiple ways.
expect(actual.map((path) => readContent(path)).sort()).toEqual(expected.sort());
});
}
});

View File

@@ -1,8 +1,9 @@
import { getMyUser, init, isHttpError } from '@immich/sdk';
import { glob } from 'fast-glob';
import { convertPathToPattern, glob } from 'fast-glob';
import { createHash } from 'node:crypto';
import { createReadStream } from 'node:fs';
import { readFile, stat, writeFile } from 'node:fs/promises';
import { platform } from 'node:os';
import { join, resolve } from 'node:path';
import yaml from 'yaml';
@@ -106,6 +107,11 @@ export interface CrawlOptions {
exclusionPattern?: string;
extensions: string[];
}
const convertPathToPatternOnWin = (path: string) => {
return platform() === 'win32' ? convertPathToPattern(path) : path;
};
export const crawl = async (options: CrawlOptions): Promise<string[]> => {
const { extensions: extensionsWithPeriod, recursive, pathsToCrawl, exclusionPattern, includeHidden } = options;
const extensions = extensionsWithPeriod.map((extension) => extension.replace('.', ''));
@@ -124,11 +130,11 @@ export const crawl = async (options: CrawlOptions): Promise<string[]> => {
if (stats.isFile() || stats.isSymbolicLink()) {
crawledFiles.push(absolutePath);
} else {
patterns.push(absolutePath);
patterns.push(convertPathToPatternOnWin(absolutePath));
}
} catch (error: any) {
if (error.code === 'ENOENT') {
patterns.push(currentPath);
patterns.push(convertPathToPatternOnWin(currentPath));
} else {
throw error;
}

View File

@@ -2,6 +2,7 @@ import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
resolve: { alias: { src: '/src' } },
build: {
rollupOptions: {
input: 'src/index.ts',

View File

@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.34.0"
constraints = "4.34.0"
version = "4.38.0"
constraints = "4.38.0"
hashes = [
"h1:+W0+Xe1AUh7yvHjDbgR9T7CY1UbBC3Y6U7Eo+ucLnJM=",
"h1:2+1lKObDDdFZRluvROF3RKtXD66CFT3PfnHOvR6CmfA=",
"h1:7vluN2wmw8D9nI11YwTgoGv3hGDXlkt8xqQ4L/JABeQ=",
"h1:B0Urm8ZKTJ8cXzSCtEpJ+o+LsD8MXaD6LU59qVbh50Q=",
"h1:FpGLCm5oF12FaRti3E4iQJlkVbdCC7toyGVuH8og7KY=",
"h1:FunTmrCMDy+rom7YskY0WiL5/Y164zFrrD9xnBxU5NY=",
"h1:GrxZhEb+5HzmHF/BvZBdGKBJy6Wyjme0+ABVDz/63to=",
"h1:J36dda2K42/oTfHuZ4jKkW5+nI6BTWFRUvo60P17NJg=",
"h1:Kq0Wyn+j6zoQeghMYixbnfnyP9ZSIEJbOCzMbaCiAQQ=",
"h1:TKxunXCiS/z105sN/kBNFwU6tIKD67JKJ3ZKjwzoCuI=",
"h1:TR0URKFQxsRO5/v7bKm5hkD/CTTjsG7aVGllL/Mf25c=",
"h1:V+3Qs0Reb6r+8p4XjE5ZFDWYrOIN0x5SwORz4wvHOJ4=",
"h1:mZB3Ui7V/lPQMQK53eBOjIHcrul74252dT06Kgn3J+s=",
"h1:wJwZrIXxoki8omXLJ7XA7B1KaSrtcLMJp090fRtFRAc=",
"zh:02aa46743c1585ada8faa7db23af68ea614053a506f88f05d1090ff5e0e68076",
"zh:1e1a545e83e6457a0e15357b23139bc288fb4fbd5e9a5ddfedc95a6a0216b08c",
"zh:29eef2621e0b1501f620e615bf73b1b90d5417d745e38af63634bc03250faf87",
"zh:3c20989d7e1e141882e6091384bf85fdc83f70f3d29e3e047c493a07de992095",
"zh:3d39619379ba29c7ffb15196f0ea72a04c84cfcdf4b39ac42ac4cf4c19f3eae2",
"zh:805f4a2774e9279c590b8214aabe6df9dcc22bb995df2530513f2f78c647ce75",
"h1:+27KAHKHBDvv3dqyJv5vhtdKQZJzoZXoMqIyronlHNw=",
"h1:/uV9RgOUhkxElkHhWs8fs5ZbX9vj6RCBfP0oJO0JF30=",
"h1:1DNAdMugJJOAWD/XYiZenYYZLy7fw2ctjT4YZmkRCVQ=",
"h1:1wn4PmCLdT7mvd74JkCGmJDJxTQDkcxc+1jNbmwnMHA=",
"h1:BIHB4fBxHg2bA9KbL92njhyctxKC8b6hNDp60y5QBss=",
"h1:HCQpvKPsMsR4HO5eDqt+Kao7T7CYeEH7KZIO7xMcC6M=",
"h1:HTomuzocukpNLwtWzeSF3yteCVsyVKbwKmN66u9iPac=",
"h1:YDxsUBhBAwHSXLzVwrSlSBOwv1NvLyry7s5SfCV7VqQ=",
"h1:dchVhxo+Acd1l2RuZ88tW9lWj4422QMfgtxKvKCjYrw=",
"h1:eypa+P4ZpsEGMPFuCE+6VkRefu0TZRFmVBOpK+PDOPY=",
"h1:f3yjse2OsRZj7ZhR7BLintJMlI4fpyt8HyDP/zcEavw=",
"h1:mSJ7xj8K+xcnEmGg7lH0jjzyQb157wH94ULTAlIV+HQ=",
"h1:tt+2J2Ze8VIdDq2Hr6uHlTJzAMBRpErBwTYx0uD5ilE=",
"h1:uQW8SKxmulqrAisO+365mIf2FueINAp5PY28bqCPCug=",
"zh:171ab67cccceead4514fafb2d39e4e708a90cce79000aaf3c29aab7ed4457071",
"zh:18aa7228447baaaefc49a43e8eff970817a7491a63d8937e796357a3829dd979",
"zh:2cbaab6092e81ba6f41fa60a50f14e980c8ec327ee11d0b21f16a478be4b7567",
"zh:53b8e49c06f5b31a8c681f8c0669cf43e78abe71657b8182a221d096bb514965",
"zh:6037cfc60b4b647aabae155fcb46d649ed7c650e0287f05db52b2068f1e27c8a",
"zh:62460982ce1a869eebfca675603fbbd50416cf6b69459fb855bfbe5ae2b97607",
"zh:65f6f3a8470917b6398baa5eb4f74b3932b213eac7c0202798bfad6fd1ee17df",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8af716f8655a57aa986861a8a7fa1d724594a284bd77c870eaea4db5f8b9732d",
"zh:a3d13c93b4e6ee6004782debaa9a17f990f2fe8ec8ba545c232818bb6064aba9",
"zh:bfa136acf82d3719473c0064446cc16d1b0303d98b06f55f503b7abeebceadb1",
"zh:ca6cf9254ae5436f2efbc01a0e3f7e4aa3c08b45182037b3eb3eb9539b2f7aec",
"zh:cba32d5de02674004e0a5955bd5222016d9991ca0553d4bd3bea517cd9def6ab",
"zh:d22c8cd527c6d0e84567f57be5911792e2fcd5969e3bba3747489f18bb16705b",
"zh:e4eeede9b3e72cdadd6cc252d4cbcf41baee6ecfd12bacd927e2dcbe733ab210",
"zh:facdaa787a69f86203cd3cc6922baea0b4a18bd9c36b0a8162e2e88ef6c90655",
"zh:8b5cebe64bf04105a49178a165b6a8800a9a33bae6767143a47fe4977755f805",
"zh:a5596635db0993ee3c3060fbc2227d91b239466e96d2d82642625a5aa2486988",
"zh:b3a9c63038441f13c311fd4b2c7e69e571445e5a7365a20c7cc9046b7e6c8aba",
"zh:b585e7e4d7648a540b14b9182819214896ca9337729eeb1f2034833b17db754d",
"zh:d2c3c545318ac8542369e9fc8228e29ee585febdf203a450fad3e0eded71ce02",
"zh:e95dd2d6c3525073af47d47b763cb81b6a51b20cabf76f789c69328922da9ecf",
"zh:eee6e590b36d6c6168a7daae8afa74a8721fd7aa9f62a710f04a311975100722",
]
}

View File

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

View File

@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.34.0"
constraints = "4.34.0"
version = "4.38.0"
constraints = "4.38.0"
hashes = [
"h1:+W0+Xe1AUh7yvHjDbgR9T7CY1UbBC3Y6U7Eo+ucLnJM=",
"h1:2+1lKObDDdFZRluvROF3RKtXD66CFT3PfnHOvR6CmfA=",
"h1:7vluN2wmw8D9nI11YwTgoGv3hGDXlkt8xqQ4L/JABeQ=",
"h1:B0Urm8ZKTJ8cXzSCtEpJ+o+LsD8MXaD6LU59qVbh50Q=",
"h1:FpGLCm5oF12FaRti3E4iQJlkVbdCC7toyGVuH8og7KY=",
"h1:FunTmrCMDy+rom7YskY0WiL5/Y164zFrrD9xnBxU5NY=",
"h1:GrxZhEb+5HzmHF/BvZBdGKBJy6Wyjme0+ABVDz/63to=",
"h1:J36dda2K42/oTfHuZ4jKkW5+nI6BTWFRUvo60P17NJg=",
"h1:Kq0Wyn+j6zoQeghMYixbnfnyP9ZSIEJbOCzMbaCiAQQ=",
"h1:TKxunXCiS/z105sN/kBNFwU6tIKD67JKJ3ZKjwzoCuI=",
"h1:TR0URKFQxsRO5/v7bKm5hkD/CTTjsG7aVGllL/Mf25c=",
"h1:V+3Qs0Reb6r+8p4XjE5ZFDWYrOIN0x5SwORz4wvHOJ4=",
"h1:mZB3Ui7V/lPQMQK53eBOjIHcrul74252dT06Kgn3J+s=",
"h1:wJwZrIXxoki8omXLJ7XA7B1KaSrtcLMJp090fRtFRAc=",
"zh:02aa46743c1585ada8faa7db23af68ea614053a506f88f05d1090ff5e0e68076",
"zh:1e1a545e83e6457a0e15357b23139bc288fb4fbd5e9a5ddfedc95a6a0216b08c",
"zh:29eef2621e0b1501f620e615bf73b1b90d5417d745e38af63634bc03250faf87",
"zh:3c20989d7e1e141882e6091384bf85fdc83f70f3d29e3e047c493a07de992095",
"zh:3d39619379ba29c7ffb15196f0ea72a04c84cfcdf4b39ac42ac4cf4c19f3eae2",
"zh:805f4a2774e9279c590b8214aabe6df9dcc22bb995df2530513f2f78c647ce75",
"h1:+27KAHKHBDvv3dqyJv5vhtdKQZJzoZXoMqIyronlHNw=",
"h1:/uV9RgOUhkxElkHhWs8fs5ZbX9vj6RCBfP0oJO0JF30=",
"h1:1DNAdMugJJOAWD/XYiZenYYZLy7fw2ctjT4YZmkRCVQ=",
"h1:1wn4PmCLdT7mvd74JkCGmJDJxTQDkcxc+1jNbmwnMHA=",
"h1:BIHB4fBxHg2bA9KbL92njhyctxKC8b6hNDp60y5QBss=",
"h1:HCQpvKPsMsR4HO5eDqt+Kao7T7CYeEH7KZIO7xMcC6M=",
"h1:HTomuzocukpNLwtWzeSF3yteCVsyVKbwKmN66u9iPac=",
"h1:YDxsUBhBAwHSXLzVwrSlSBOwv1NvLyry7s5SfCV7VqQ=",
"h1:dchVhxo+Acd1l2RuZ88tW9lWj4422QMfgtxKvKCjYrw=",
"h1:eypa+P4ZpsEGMPFuCE+6VkRefu0TZRFmVBOpK+PDOPY=",
"h1:f3yjse2OsRZj7ZhR7BLintJMlI4fpyt8HyDP/zcEavw=",
"h1:mSJ7xj8K+xcnEmGg7lH0jjzyQb157wH94ULTAlIV+HQ=",
"h1:tt+2J2Ze8VIdDq2Hr6uHlTJzAMBRpErBwTYx0uD5ilE=",
"h1:uQW8SKxmulqrAisO+365mIf2FueINAp5PY28bqCPCug=",
"zh:171ab67cccceead4514fafb2d39e4e708a90cce79000aaf3c29aab7ed4457071",
"zh:18aa7228447baaaefc49a43e8eff970817a7491a63d8937e796357a3829dd979",
"zh:2cbaab6092e81ba6f41fa60a50f14e980c8ec327ee11d0b21f16a478be4b7567",
"zh:53b8e49c06f5b31a8c681f8c0669cf43e78abe71657b8182a221d096bb514965",
"zh:6037cfc60b4b647aabae155fcb46d649ed7c650e0287f05db52b2068f1e27c8a",
"zh:62460982ce1a869eebfca675603fbbd50416cf6b69459fb855bfbe5ae2b97607",
"zh:65f6f3a8470917b6398baa5eb4f74b3932b213eac7c0202798bfad6fd1ee17df",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8af716f8655a57aa986861a8a7fa1d724594a284bd77c870eaea4db5f8b9732d",
"zh:a3d13c93b4e6ee6004782debaa9a17f990f2fe8ec8ba545c232818bb6064aba9",
"zh:bfa136acf82d3719473c0064446cc16d1b0303d98b06f55f503b7abeebceadb1",
"zh:ca6cf9254ae5436f2efbc01a0e3f7e4aa3c08b45182037b3eb3eb9539b2f7aec",
"zh:cba32d5de02674004e0a5955bd5222016d9991ca0553d4bd3bea517cd9def6ab",
"zh:d22c8cd527c6d0e84567f57be5911792e2fcd5969e3bba3747489f18bb16705b",
"zh:e4eeede9b3e72cdadd6cc252d4cbcf41baee6ecfd12bacd927e2dcbe733ab210",
"zh:facdaa787a69f86203cd3cc6922baea0b4a18bd9c36b0a8162e2e88ef6c90655",
"zh:8b5cebe64bf04105a49178a165b6a8800a9a33bae6767143a47fe4977755f805",
"zh:a5596635db0993ee3c3060fbc2227d91b239466e96d2d82642625a5aa2486988",
"zh:b3a9c63038441f13c311fd4b2c7e69e571445e5a7365a20c7cc9046b7e6c8aba",
"zh:b585e7e4d7648a540b14b9182819214896ca9337729eeb1f2034833b17db754d",
"zh:d2c3c545318ac8542369e9fc8228e29ee585febdf203a450fad3e0eded71ce02",
"zh:e95dd2d6c3525073af47d47b763cb81b6a51b20cabf76f789c69328922da9ecf",
"zh:eee6e590b36d6c6168a7daae8afa74a8721fd7aa9f62a710f04a311975100722",
]
}

View File

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

View File

@@ -26,6 +26,16 @@ services:
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
environment:
IMMICH_REPOSITORY: immich-app/immich
IMMICH_REPOSITORY_URL: https://github.com/immich-app/immich
IMMICH_SOURCE_REF: local
IMMICH_SOURCE_COMMIT: af2efbdbbddc27cd06142f22253ccbbbbeec1f55
IMMICH_SOURCE_URL: https://github.com/immich-app/immich/commit/af2efbdbbddc27cd06142f22253ccbbbbeec1f55
IMMICH_BUILD: '9654404849'
IMMICH_BUILD_URL: https://github.com/immich-app/immich/actions/runs/9654404849
IMMICH_BUILD_IMAGE: development
IMMICH_BUILD_IMAGE_URL: https://github.com/immich-app/immich/pkgs/container/immich-server
ulimits:
nofile:
soft: 1048576
@@ -36,6 +46,8 @@ services:
depends_on:
- redis
- database
healthcheck:
disable: false
immich-web:
container_name: immich_web
@@ -81,10 +93,12 @@ services:
depends_on:
- database
restart: unless-stopped
healthcheck:
disable: false
redis:
container_name: immich_redis
image: redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900
image: redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e
healthcheck:
test: redis-cli ping || exit 1
@@ -103,11 +117,26 @@ services:
ports:
- 5432:5432
healthcheck:
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --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
start_interval: 30s
start_period: 5m
command: ["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"]
command:
[
'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',
]
# set IMMICH_METRICS=true in .env to enable metrics
# immich-prometheus:

View File

@@ -21,6 +21,8 @@ services:
- redis
- database
restart: always
healthcheck:
disable: false
immich-machine-learning:
container_name: immich_machine_learning
@@ -33,15 +35,19 @@ services:
dockerfile: Dockerfile
args:
- DEVICE=cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference
ports:
- 3003:3003
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
healthcheck:
disable: false
redis:
container_name: immich_redis
image: redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900
image: redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e
healthcheck:
test: redis-cli ping || exit 1
restart: always
@@ -61,11 +67,11 @@ services:
ports:
- 5432:5432
healthcheck:
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --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
start_interval: 30s
start_period: 5m
command: ["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"]
command: ["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"]
restart: always
# set IMMICH_METRICS=true in .env to enable metrics
@@ -73,7 +79,7 @@ services:
container_name: immich_prometheus
ports:
- 9090:9090
image: prom/prometheus@sha256:5c435642ca4d8427ca26f4901c11114023004709037880cd7860d5b7176aa731
image: prom/prometheus@sha256:cafe963e591c872d38f3ea41ff8eb22cee97917b7c97b5c0ccd43a419f11f613
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
@@ -85,7 +91,7 @@ services:
command: ['./run.sh', '-disable-reporting']
ports:
- 3000:3000
image: grafana/grafana:11.0.0-ubuntu@sha256:dcd3ae78713958a862732c3608d32c03f0c279c35a2032d74b80b12c5cdc47b8
image: grafana/grafana:11.1.3-ubuntu@sha256:e10453733015f31103cb530425f32c994816b50102886fa885dafea2c50a711c
volumes:
- grafana-data:/var/lib/grafana

View File

@@ -16,6 +16,7 @@ services:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes:
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
env_file:
@@ -26,6 +27,8 @@ services:
- redis
- database
restart: always
healthcheck:
disable: false
immich-machine-learning:
container_name: immich_machine_learning
@@ -40,10 +43,12 @@ services:
env_file:
- .env
restart: always
healthcheck:
disable: false
redis:
container_name: immich_redis
image: docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900
image: docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e
healthcheck:
test: redis-cli ping || exit 1
restart: always
@@ -57,13 +62,14 @@ services:
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
healthcheck:
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --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
start_interval: 30s
start_period: 5m
command: ["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"]
command: ["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"]
restart: always
volumes:

View File

@@ -12,6 +12,7 @@ DB_DATA_LOCATION=./postgres
IMMICH_VERSION=release
# Connection secret for postgres. You should change it to a random password
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
DB_PASSWORD=postgres
# The values below this line do not need to be changed

View File

@@ -43,7 +43,7 @@ if [ -n "${quota:-}" ] && [ -n "${period:-}" ]; then
cpus=1
fi
else
cpus=$(grep -c processor /proc/cpuinfo)
cpus=$(grep -c ^processor /proc/cpuinfo)
fi
echo "$cpus"

View File

@@ -1 +1 @@
20.14
20.16.0

View File

@@ -94,7 +94,7 @@ Thank you, and I am asking for your support for the project. I hope to be a full
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
Join our friendly [Discord](https://discord.gg/D8JsnBEuKb) to talk and discuss Immich, tech, or anything
Join our friendly [Discord](https://discord.immich.app) to talk and discuss Immich, tech, or anything
Cheer!

View File

@@ -142,7 +142,7 @@ Thank you, and I am asking for your support for the project. I hope to be a full
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
Join our friendly [Discord](https://discord.gg/D8JsnBEuKb) to talk and discuss Immich, tech, or anything
Join our friendly [Discord](https://discord.immich.app) to talk and discuss Immich, tech, or anything
Cheer!

View File

@@ -1,7 +1,7 @@
---
title: The Immich core team goes full-time
authors: [alextran]
tags: [update, announcement, futo]
tags: [update, announcement, FUTO]
date: 2024-05-01T00:00
---

View File

@@ -0,0 +1,91 @@
---
title: Licensing announcement - Purchase a license to support Immich
authors: [alextran]
tags: [update, announcement, FUTO]
date: 2024-07-18T00:00
---
Hello everybody,
Firstly, on behalf of the Immich team, I'd like to thank everybody for your continuous support of Immich since the very first day! Your contributions, encouragement, and community engagement have helped bring Immich to its current state. The team and I are forever grateful for that.
Since our [last announcement of the core team joining FUTO to work on Immich full-time](https://immich.app/blog/2024/immich-core-team-goes-fulltime), one of the goals of our new position is to foster a healthy relationship between the developers and the users. We believe that this enables us to create great software, establish transparent policies and build trust.
We want to build a great software application that brings value to you and your loved ones' lives. We are not using you as a product, i.e., selling or tracking your data. We are not putting annoying ads into our software. We respect your privacy. We want to be compensated for the hard work we put in to build Immich for you.
With those notes, we have enabled a way for you to financially support the continued development of Immich, ensuring the software can move forward and will be maintained, by offering a lifetime license of the software. We think if you like and use software, you should pay for it, but _we're never going to force anyone to pay or try to limit Immich for those who don't._
There are two types of license that you can choose to purchase: **Server License** and **Individual License**.
### Server License
This is a lifetime license costing **$99.99**. The license is applied to the whole server. You and all users that use your server are licensed.
### Individual License
This is a lifetime license costing **$24.99**. The license is applied to a single user, and can be used on any server they choose to connect to.
<img
width="837"
alt="license-social-gh"
src="https://github.com/user-attachments/assets/241932ed-ef3b-44ec-a9e2-ee80754e0cca"
/>
You can purchase the license on [our page - https://buy.immich.app](https://buy.immich.app).
Starting with release `v1.109.0` you can purchase and enter your purchased license key directly in the app.
<img
width="1414"
alt="license-page-gh"
src="https://github.com/user-attachments/assets/364fc32a-f6ef-4594-9fea-28d5a26ad77c"
/>
## Thank you
Thank you again for your support, this will help create a strong foundation and stability for the Immich team to continue developing and maintaining the project that you love to use.
<p align="center">
<img
src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExbjY2eWc5Y2F0ZW56MmR4aWE0dDhzZXlidXRmYWZyajl1bWZidXZpcyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/87CKDqErVfMqY/giphy.gif"
width="550"
title="SUPPORT THE PROJECT!"
/>
</p>
<br />
<br />
Cheers! 🎉
Immich team
# FAQ
### 1. Where can I purchase a license?
There are several places where you can purchase the license from
- [https://buy.immich.app](https://buy.immich.app)
- [https://pay.futo.org](https://pay.futo.org/)
- or directly from the app.
### 2. Do I need both _Individual License_ and _Server License_?
No,
If you are the admin and the sole user, or your instance has less than a total of 4 users, you can buy the **Individual License** for each user.
If your instance has more than 4 users, it is more cost-effective to buy the **Server License**, which will license all the users on your instance.
### 3. What do I do if I don't pay?
You can continue using Immich without any restriction.
### 4. Will there be any paywalled features?
No, there will never be any paywalled features.
### 5. Where can I get support regarding payment issues?
You can email us with your `orderId` and your email address `billing@futo.org` or on our Discord server.

View File

@@ -0,0 +1,78 @@
---
title: Immich Update - July 2024
authors: [alextran]
date: 2024-07-01T00:00
tags: [update, v1.106.0]
---
Hello everybody! Alex from Immich here and I am back with another development progress update for the project.
Summer has returned once again, and the night sky is filled with stars, thank you for **38_000 shining stars** you have sent to our [GitHub repo](https://github.com/immich-app/immich)! Since the last announcement several core contributors have started full time. Everything is going great with development, PRs get merged with _brrrrrrr_ rate, conversation exchange between team members is on a new high, we met and are working with the great engineers at FUTO. The spirit is high and we have a lot of things brewing that we think you will like.
Let's go over some of the updates we had since the last post.
### Container consolidation
Reduced the number of total containers from 5 to 4 by making the microservices thread get spawned directly in the server container. Woohoo, remember when Immich had 7 containers?
### Email notifications
![smtp](https://github.com/immich-app/immich/assets/27055614/949cba85-d3f1-4cd3-b246-a6f5fb5d3ae8)
We added email notifications to the app with SMTP settings that you can configure for the following events
- A new account is created for you.
- You are added to a shared album.
- New media is added to an album.
### Versioned docs
You can now jump back into the past or take a peek at the unreleased version of the documentation by selecting the version on the website.
![version-doc](https://github.com/immich-app/immich/assets/27055614/6d22898a-5093-41ad-b416-4573d7ce6e03)
### Similarity deduplication
With more machine learning and CLIP magic, we now have similarity deduplication built into the application where it will search for closely similar images and let you decide what to do with them; i.e keep or trash.
![similarity-deduplication](https://github.com/immich-app/immich/assets/27055614/3cac8478-fbf7-47ea-acb6-0146901dc67e)
### Permanent URL for asset on the web
The detail view for an asset now has a permanent URL so you can easily share them with your loved ones.
### Web app translations
We now have a public Weblate project which the community can use to translate the webapp to their native languages. We are planning to port the mobile app translation to this platform as well. If you would like to contribute, you can take a look [here](https://hosted.weblate.org/projects/immich/immich/). We're already close to 50% translations -- we really appreciate everyone contributing to that!
![web-translation](https://github.com/immich-app/immich/assets/27055614/363df2ed-656c-4584-bd82-0708a693c5bc)
### Read-only/Editor mode on shared album
As the owner of the album, you can choose if the shared user can edit the album or to only view the content of the album without any modification.
![read-only-album](https://github.com/immich-app/immich/assets/27055614/c6f66375-b869-495a-9a86-3e87b316d109)
### Better video thumbnails
Immich now tries to find a descriptive video thumbnail instead of simply using the first frame. No more black images for thumbnails!
### Public Roadmap
We now have a [public roadmap](https://immich.app/roadmap), giving you a high-level overview of things the team is working on. The first goal of this roadmap is to bring Immich to a stable release, which is expected sometime later this year. Some of the highlights include
- Auto stacking - Auto stacking of burst photos
- Basic editor - Basic photo editing capabilities
- Workflows - Automate tasks with workflows
- Fine grained access controls - Granular access controls for users and api keys
- Better background backups - Rework background backups to be more reliable
- Private/locked photos - Private assets with extra protections
Beyond the items in the roadmap, we have _many many_ more ideas for Immich. The team and I hope that you are enjoying the application, find it helpful in your life and we have nothing but the intention of building out great software for you all!
Have an amazing Summer or Winter for those in the southern hemisphere! :D
Until next time,
Cheers!
Alex

View File

@@ -133,40 +133,6 @@ For example, say you have existing transcodes with the policy "Videos higher tha
No. Our design principle is that the original assets should always be untouched.
### How can I move all data (photos, persons, albums, libraries) from one user to another?
This is not officially supported but can be accomplished with some database updates. You can do this on the command line (in the PostgreSQL container using the `psql` command), or you can add, for example, an [Adminer](https://www.adminer.org/) container to the `docker-compose.yml` file so that you can use a web interface.
<details>
<summary>Steps</summary>
1. **MAKE A BACKUP** - See [backup and restore](/docs/administration/backup-and-restore.md).
2. Find the ID of both the 'source' and the 'destination' user (it's the id column in the `users` table)
3. Four tables need to be updated:
```sql
BEGIN;
-- reassign albums
UPDATE albums SET "ownerId" = '<destinationId>' WHERE "ownerId" = '<sourceId>';
-- reassign people
UPDATE person SET "ownerId" = '<destinationId>' WHERE "ownerId" = '<sourceId>';
-- reassign assets
UPDATE assets SET "ownerId" = '<destinationId>' WHERE "ownerId" = '<sourceId>'
AND CHECKSUM NOT IN (SELECT CHECKSUM FROM assets WHERE "ownerId" = '<destinationId>');
-- reassign external libraries
UPDATE libraries SET "ownerId" = '<destinationId>' WHERE "ownerId" = '<sourceId>';
COMMIT;
```
4. There might be left-over assets in the 'source' user's library if they are skipped by the last query because of duplicate checksums. These are probably duplicates anyway, and can probably be removed.
</details>
---
## Albums
@@ -201,7 +167,7 @@ Immich uses CLIP models. For more information about CLIP and its capabilities, r
### How does facial recognition work?
For face detection and recognition, Immich uses [InsightFace models](https://github.com/deepinsight/insightface/tree/master/model_zoo).
See [How Facial Recognition Works](/docs/features/facial-recognition#How-Facial-Recognition-Works) for details.
### How can I disable machine learning?
@@ -215,19 +181,15 @@ However, disabling all jobs will not disable the machine learning service itself
### I'm getting errors about models being corrupt or failing to download. What do I do?
You can delete the model cache volume, where models are downloaded. This will give the service a clean environment to download the model again. If models are failing to download entirely, you can manually download them from [Huggingface][huggingface] and place them in the cache folder.
You can delete the model cache volume, where models are downloaded. This will give the service a clean environment to download the model again. If models are failing to download entirely, you can manually download them from [Hugging Face][huggingface] and place them in the cache folder.
### Can I use a custom CLIP model?
No, this is not supported. Only models listed in the [Huggingface][huggingface] page are compatible. Feel free to make a feature request if there's a model not listed here that you think should be added.
No, this is not supported. Only models listed in the [Hugging Face][huggingface] page are compatible. Feel free to make a feature request if there's a model not listed here that you think should be added.
### I want to be able to search in other languages besides English. How can I do that?
You can change to a multilingual model listed [here](https://huggingface.co/collections/immich-app/multilingual-clip-654eb08c2382f591eeb8c2a7) by going to Administration > Machine Learning Settings > Smart Search and replacing the name of the model. Be sure to re-run Smart Search on all assets after this change. You can then search in over 100 languages.
:::note
Feel free to make a feature request if there's a model you want to use that isn't in [Immich Huggingface list][huggingface].
:::
You can change to a multilingual CLIP model. See [here](/docs/features/smart-search#CLIP-model) for instructions.
### Does Immich support Facial Recognition for videos?
@@ -268,7 +230,7 @@ ls clip/ facial-recognition/
### Why is Immich slow on low-memory systems like the Raspberry Pi?
Immich optionally uses machine learning for several features. However, it can be too heavy to run on a Raspberry Pi. You can [mitigate](/docs/FAQ#can-i-lower-cpu-and-ram-usage) this or host Immich's machine-learning container on a [more powerful system](/docs/guides/remote-machine-learning), or [disable](/docs/FAQ#how-can-i-disable-machine-learning) machine learning entirely.
Immich optionally uses transcoding and machine learning for several features. However, it can be too heavy to run on a Raspberry Pi. You can [mitigate](/docs/FAQ#can-i-lower-cpu-and-ram-usage) this or host Immich's machine-learning container on a [more powerful system](/docs/guides/remote-machine-learning), or [disable](/docs/FAQ#how-can-i-disable-machine-learning) machine learning entirely.
### Can I lower CPU and RAM usage?
@@ -277,10 +239,12 @@ The initial backup is the most intensive due to the number of jobs running. The
- Lower the job concurrency for these jobs to 1.
- Under Settings > Transcoding Settings > Threads, set the number of threads to a low number like 1 or 2.
- Under Settings > Machine Learning Settings > Facial Recognition > Model Name, you can change the facial recognition model to `buffalo_s` instead of `buffalo_l`. The former is a smaller and faster model, albeit not as good.
- For facial recognition on new images to work properly, You must re-run the Face Detection job for all images after this.
- For facial recognition on new images to work properly, You must re-run the Face Detection job for all images after this.
- At the container level, you can [set resource constraints](/docs/FAQ#can-i-limit-cpu-and-ram-usage) to lower usage further.
- It's recommended to only apply these constraints _after_ taking some of the measures here for best performance.
- If these changes are not enough, see [below](/docs/FAQ#how-can-i-disable-machine-learning) for instructions on how to disable machine learning.
### Can I limit the amount of CPU and RAM usage?
### Can I limit CPU and RAM usage?
By default, a container has no resource constraints and can use as much of a given resource as the host's kernel scheduler allows. To limit this, you can add the following to the `docker-compose.yml` block of any containers that you want to have limited resources.
@@ -300,6 +264,8 @@ deploy:
</details>
For more details, you can look at the [original docker docs](https://docs.docker.com/config/containers/resource_constraints/) or use this [guide](https://www.baeldung.com/ops/docker-memory-limit).
Note that memory constraints work by terminating the container, so this can introduce instability if set too low.
### How can I boost machine learning speed?
:::note
@@ -309,21 +275,16 @@ This advice improves throughput, not latency. This is to say that it will make S
You can increase throughput by increasing the job concurrency for machine learning jobs (Smart Search, Face Detection). With higher concurrency, the host will work on more assets in parallel. You can do this by navigating to Administration > Settings > Job Settings and increasing concurrency as needed.
:::danger
On a normal machine, 2 or 3 concurrent jobs can probably max the CPU. Beyond this, note that storage speed and latency may quickly become the limiting factor; particularly when using HDDs.
On a normal machine, 2 or 3 concurrent jobs can probably max the CPU. Storage speed and latency can quickly become the limiting factor beyond this, particularly when using HDDs.
Do not exaggerate with the amount of jobs because you're probably thoroughly overloading the server.
The concurrency can be increased more comfortably with a GPU, but should still not be above 16 in most cases.
More details can be found [here](https://discord.com/channels/979116623879368755/994044917355663450/1174711719994605708)
Do not exaggerate with the job concurrency because you're probably thoroughly overloading the server.
:::
### Why is Immich using so much of my CPU?
### My server shows Server Status Offline | Version Unknown. What can I do?
When a large number of assets are uploaded to Immich, it makes sense that the CPU and RAM will be heavily used for machine learning work and creating image thumbnails.
Once this process is completed, the percentage of CPU usage will drop to around 3-5% usage
### My server shows Server Status Offline | Version Unknown what can I do?
You need to enable Websocket on your reverse proxy.
You need to enable WebSockets on your reverse proxy.
---
@@ -333,6 +294,12 @@ You need to enable Websocket on your reverse proxy.
Immich components are typically deployed using docker. To see logs for deployed docker containers, you can use the [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/), specifically the `docker logs` command. For examples, see [Docker Help](/docs/guides/docker-help.md).
### How can I reduce the log verbosity of Redis?
To decrease Redis logs, you can add the following line to the `redis:` section of the `docker-compose.yml`:
` command: redis-server --loglevel warning`
### How can I run Immich as a non-root user?
You can change the user in the container by setting the `user` argument in `docker-compose.yml` for each service.
@@ -442,4 +409,11 @@ docker exec -it immich_postgres psql --dbname=immich --username=<DB_USERNAME> --
</details>
If corruption is detected, you should immediately make a backup before performing any other work in the database.
To do so, you may need to set the `zero_damaged_pages=on` flag for the database server to allow `pg_dumpall` to succeed.
After taking a backup, the recommended next step is to restore the database from a healthy backup before corruption was detected.
The damaged database dump can be used to manually recover any changes made since the last backup, if needed.
The causes of possible corruption are many, but can include unexpected poweroffs or unmounts, use of a network share for Postgres data, or a poor storage medium such an SD card or failing HDD/SSD.
[huggingface]: https://huggingface.co/immich-app

View File

@@ -76,6 +76,7 @@ services:
backup:
container_name: immich_db_dumper
image: prodrigestivill/postgres-backup-local:14
restart: always
env_file:
- .env
environment:
@@ -148,9 +149,21 @@ for more info read the [release notes](https://github.com/immich-app/immich/rele
- Preview images (small thumbnails and large previews) for each asset and thumbnails for recognized faces.
- Stored in `UPLOAD_LOCATION/thumbs/<userID>`.
- **Encoded Assets:**
- Videos that have been re-encoded from the original for wider compatibility. The original is not removed.
- Stored in `UPLOAD_LOCATION/encoded-video/<userID>`.
- **Postgres**
- The Immich database containing all the information to allow the system to function properly.
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
- Stored in `UPLOAD_LOCATION/postgres`.
:::danger
A backup of this folder does not constitute a backup of your database!
Follow the instructions listed [here](/docs/administration/backup-and-restore#database) to learn how to perform a proper backup.
:::
</TabItem>
<TabItem value="Storage Template On" label="Storage Template On">
@@ -186,11 +199,22 @@ When you turn off the storage template engine, it will leave the assets in `UPLO
- Files uploaded through mobile apps.
- Temporarily located in `UPLOAD_LOCATION/upload/<userID>`.
- Transferred to `UPLOAD_LOCATION/library/<userID>` upon successful upload.
- **Postgres**
- The Immich database containing all the information to allow the system to function properly.
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
- Stored in `UPLOAD_LOCATION/postgres`.
:::danger
A backup of this folder does not constitute a backup of your database!
Follow the instructions listed [here](/docs/administration/backup-and-restore#database) to learn how to perform a proper backup.
:::
</TabItem>
</Tabs>
:::danger
Do not touch the files inside these folders under any circumstances except taking a backup, changing or removing an asset can cause untracked and missing files.
Do not touch the files inside these folders under any circumstances except taking a backup. Changing or removing an asset can cause untracked and missing files.
You can think of it as App-Which-Must-Not-Be-Named, the only access to viewing, changing and deleting assets is only through the mobile or browser interface.
:::

View File

@@ -27,7 +27,7 @@ Copy the entire `immich-server` block as a new service and make the following ch
+ container_name: immich_microservices
```
Once you have two copies of the immich-server service, make the following chnages to each one. This will allow one container to only serve the web UI and API, and the other one to handle all other tasks.
Once you have two copies of the immich-server service, make the following changes to each one. This will allow one container to only serve the web UI and API, and the other one to handle all other tasks.
```diff
services:

View File

@@ -24,7 +24,7 @@ This environment includes the services below. Additional details are available i
- Web app - [`/web`](https://github.com/immich-app/immich/tree/main/web)
- Machine learning - [`/machine-learning`](https://github.com/immich-app/immich/tree/main/machine-learning)
- Redis
- PostgreSQL development database with exposed port `5432` so you can use any database client to acess it
- PostgreSQL development database with exposed port `5432` so you can use any database client to access it
All the services are packaged to run as with single Docker Compose command.

View File

@@ -4,7 +4,8 @@
### Unit tests
Unit are run by calling `npm run test` from the `server` directory.
Unit are run by calling `npm run test` from the `server/` directory.
You need to run `npm install` (in `server/`) before _once_.
### End to end tests
@@ -14,6 +15,11 @@ The e2e tests can be run by first starting up a test production environment via:
make e2e
```
Before you can run the tests, you need to run the following commands _once_:
- `npm install` (in `e2e/`)
- `make open-api` (in the project root `/`)
Once the test environment is running, the e2e tests can be run via:
```bash

View File

@@ -0,0 +1,21 @@
# Translations
:::tip
You can request a new language [here](https://hosted.weblate.org/new-lang/immich/immich/).
:::
## Weblate
[Weblate](https://weblate.org/) is a "libre software web-based continuous localization system". Immich localization efforts are managed on their [hosted platform](https://hosted.weblate.org/projects/immich/immich/).
## International message format
Plurals, numbers, dates and other locale specific message formats can be handled by using the [ICU message format](https://unicode-org.github.io/icu/userguide/format_parse/messages/). Internally, this is handled by the [intl-messageformat](https://www.npmjs.com/package/intl-messageformat) library. Their [documentation](https://formatjs.io/docs/intl-messageformat/) includes common, editable examples via a "live editor" feature, which can be useful to test and debug message formats.
## Progress
Immich currently supports the following languages:
<a href="https://hosted.weblate.org/engage/immich/">
<img src="https://hosted.weblate.org/widget/immich/immich/multi-auto.svg" alt="Translation status" />
</a>

View File

@@ -1,7 +1,7 @@
# Troubleshooting
:::tip
A great option to get assistance with troubleshooting is to join our [Discord](https://discord.gg/D8JsnBEuKb) server, where we have a dedicated channel for `#contributing`.
A great option to get assistance with troubleshooting is to join our [Discord](https://discord.immich.app) server, where we have a dedicated channel for `#contributing`.
:::
## Known Issues

View File

@@ -2,7 +2,7 @@
## Overview
Immich recognizes faces in your photos and videos and groups them together. You can then assign names to the faces and search for them.
Immich recognizes faces in your photos and videos and groups them together into people. You can then assign names to these people and search for them.
The list of people is shown in the Explore page.
@@ -18,13 +18,75 @@ The asset detail view will also show the faces that are recognized in the asset.
## Actions
Additional actions you can do with a detected person are:
Additional actions you can do include:
- Change the feature face photo of the person
- Set date of birth
- Merge two or more detected faces into one person
- Hide face
- Changing the feature photo of the person
- Setting a person's date of birth
- Merging two or more detected faces into one person
- Hiding the faces of a person from the Explore page and detail view
- Assigning an unrecognized face to a person
It can be found from the app bar when you access the detail view of a person.
<img src={require('./img/facial-recognition-4.png').default} title='Facial Recognition 4' width="70%"/>
## How Face Detection Works
Face detection sends the generated preview image to the machine learning service for processing. The service checks if it has the relevant model downloaded and downloads it if not. The image is decoded, pre-processed and passed to the face detection model (with hardware acceleration if configured). The bounding boxes and scores outputted from this model are used to crop and preprocess the image once again to be passed to a facial recognition model (also accelerated if configured). The embeddings from the recognition model, together with the bounding boxes and scores from the face detection model, are then sent back to the server to be added to the database. The embeddings in particular are indexed so they can be searched quickly during facial recognition clustering.
## How Facial Recognition Works
The facial recognition algorithm we use is derived from [DBSCAN](https://www.youtube.com/watch?v=RDZUdRSDOok), a popular clustering algorithm. It essentially treats each detected face as a point in a graph and aims to group points that are close to each other.
:::note
An important concept is whether something is a _core point_. A core point has a minimum number of points around it within a certain distance. A non-core point can only be assigned to a cluster if it can reach a core point; a non-core point can't be used to extend a cluster even if it's part of one. In Immich, the _Minimum Recognized Faces_ setting controls the threshold to be considered a core point.
:::
For each face, it looks around it to find other faces within a certain distance. Faces within this distance are considered similar, so it then checks if any of these faces are associated with a person.
If there is an existing person, it assigns the person of the most similar face to the face being processed.
If there is none, then it has to determine something from the DBSCAN algorithm: whether the face is a _core point_. If there are a certain number of similar faces (by default 3, including the face being considered), then this face is a core point. A new person is created for this face and the face is assigned to it. When other faces are processed, if they're similar to this face, they'll see that it has an associated person and can be assigned to that person.
However, if there aren't enough similar faces, no new person will be created. Instead, the face will wait for all the other faces to be processed to see if any matches that previously didn't have an associated person now do. If they do, then the face will be assigned to that person. If not, this face will be considered an outlier, such as a stranger in the background of an image.
The algorithm has some subtle differences compared to DBSCAN:
- DBSCAN doesn't have a concept of incremental clustering: it clusters all points at once. In contrast, facial recognition has to evolve as more assets are added without re-clustering everything each time.
- The algorithm described above works within a set of queued assets. Once these faces are processed and a new round of faces are detected, the behavior will not be the same as traditional DBSCAN since it preserves the clusters (people) generated from the previous round.
- Facial recognition tries to wait for face detection and thumbnail generation to complete before starting for this reason: the larger the set of faces in the queue, the better the results will be.
- Re-running facial recognition on all assets afterwards does behave like DBSCAN, however.
- DBSCAN is designed for range-based searches (i.e. points within a distance), but high-dimensional vector indices are generally optimized for getting the closest K results. The recognition algorithm doesn't try to get _all_ similar faces within a distance for performance reasons. Instead, it searches for a small number of matches for each face. The end result should be very similar if not identical, but with possibly different performance characteristics.
- Because of this, part of the recognition process is handled during a nightly job to ensure that unassigned faces with potential matches can be recognized.
:::tip
If you didn't import your assets at once or if the server was able to process jobs faster than you could upload them, it's possible that the clustering was suboptimal. If you haven't put effort into the current results, it may be worth re-running facial recognition on all assets for the best starting point. If it's too late for that, you can also manually assign a selection of unassigned faces and queue _Missing_ for Facial Recognition to help it learn and assign more faces automatically.
:::
## Configuration
Navigating to Administration > Settings > Machine Learning Settings > Facial Recognition will show the options available.
:::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.
:::
### Facial recognition model
There are a few different models available; the default is typically considered the best. On more constrained systems where the default is too intensive, you can choose a smaller model instead.
### Minimum detection score
This setting affects whether a result from the face detecton model is filtered out as a false positive. It may seem tempting to set this low to detect more faces, but it can lead to false positives that are difficult to deal with and can harm facial recognition. It is strongly recommended not to go below 0.5 for this setting. Setting it to a very high number like 0.9 is also not recommended: the default is already biased toward precision, so a threshold that high leads to many undetected faces.
After changing this setting, it will only apply to new face detection jobs. To apply the new setting to all assets, you need to re-run face detection for all assets.
### Maximum recognition distance
The distance threshold described in How Facial Recognition Works. The default works well for most people, but it may be worth lowering it if the library has twins or otherwise very similar looking people. A threshold that's too low just means needing to merge duplicate people after facial recognition, whereas a threshold too high can produce unsalvageable results. It is strongly recommended not to go below 0.3 or above 0.7.
### Minimum recognized faces
The core point threshold described in How Facial Recognition Works. This setting has a few implications. First, it takes effect immediately in that people with fewer faces than this are hidden from view. Secondly, it makes clustering more robust as it prevents loosely-related faces from being linked to each other by requiring a certain level of density.
Increasing this setting is a good idea if you increase the recognition distance or reduce the minimum detection score. Setting it to 1 effectively disables the concept of core points, but can be an option if you prefer a more hands-on approach.

View File

@@ -60,17 +60,17 @@ For RKMPP to work:
#### Basic Setup
1. If you do not already have it, download the latest [`hwaccel.transcoding.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-microservices`, uncomment the `extends` section and change `cpu` to the appropriate backend.
2. In the `docker-compose.yml` under `immich-server`, uncomment the `extends` section and change `cpu` to the appropriate backend.
- For VAAPI on WSL2, be sure to use `vaapi-wsl` rather than `vaapi`
3. Redeploy the `immich-microservices` container with these updated settings.
3. Redeploy the `immich-server` container with these updated settings.
4. In the Admin page under `Video transcoding settings`, change the hardware acceleration setting to the appropriate option and save.
5. (Optional) If using a compatible backend, you may enable hardware decoding for optimal performance.
#### Single Compose File
Some platforms, including Unraid and Portainer, do not support multiple Compose files as of writing. As an alternative, you can "inline" the relevant contents of the [`hwaccel.transcoding.yml`][hw-file] file into the `immich-microservices` service directly.
Some platforms, including Unraid and Portainer, do not support multiple Compose files as of writing. As an alternative, you can "inline" the relevant contents of the [`hwaccel.transcoding.yml`][hw-file] file into the `immich-server` service directly.
For example, the `qsv` section in this file is:
@@ -79,21 +79,22 @@ devices:
- /dev/dri:/dev/dri
```
You can add this to the `immich-microservices` service instead of extending from `hwaccel.transcoding.yml`:
You can add this to the `immich-server` service instead of extending from `hwaccel.transcoding.yml`:
```yaml
immich-microservices:
container_name: immich_microservices
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
# Note the lack of an `extends` section
devices:
- /dev/dri:/dev/dri
command: ['start.sh', 'microservices']
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- 2283:3001
depends_on:
- redis
- database
@@ -122,6 +123,7 @@ Once this is done, you can continue to step 3 of "Basic Setup".
- You may want to choose a slower preset than for software transcoding to maintain quality and efficiency
- While you can use VAAPI with NVIDIA and Intel devices, prefer the more specific APIs since they're more optimized for their respective devices
- You can confirm the device is being recognized and used by checking its utilization (via `nvtop` for NVIDIA, `intel_gpu_top` for Intel, etc.) when transcoding. A lack of error logs when transcoding also indicates that it's being used.
[hw-file]: https://github.com/immich-app/immich/releases/latest/download/hwaccel.transcoding.yml
[nvct]: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html

View File

@@ -104,18 +104,19 @@ The `immich-server` container will need access to the gallery. Modify your docke
immich-server:
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
+ - /home/user/old-pics:/mnt/media/old-pics:ro
+ - /mnt/nas/christmas-trip:/mnt/nas/christmas-trip:ro
+ - /home/user/old-pics:/home/user/old-pics: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
+ - "C:/Users/user_name/Desktop/my media:/mnt/media/my-media:ro" # import path in Windows system.
```
:::tip
The `ro` flag at the end only gives read-only access to the volumes. While Immich does not modify files, it's a good practice to mount read-only.
The `ro` flag at the end only gives read-only access to the volumes. This will disallow the images from being deleted in the web UI.
:::
:::info
_Remember to bring the container `docker compose down/up` to register the changes. Make sure you can see the mounted path in the container._
_Remember to run `docker compose up -d` to register the changes. Make sure you can see the mounted path in the container._
:::
### Create External Libraries

View File

@@ -32,12 +32,13 @@ You do not need to redo any machine learning jobs after enabling hardware accele
- Where and how you can get this file depends on device and vendor, but typically, the device vendor also supplies these
- 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
- Optional: Configure your `.env` file, see [environment variables](/docs/install/environment-variables) for ARM NN specific settings
#### CUDA
- The GPU must have compute capability 5.2 or greater.
- The server must have the official NVIDIA driver installed.
- The installed driver must be >= 535 (it must support CUDA 12.2).
- The installed driver must be >= 545 (it must support CUDA 12.3.2).
- On Linux (except for WSL2), you also need to have [NVIDIA Container Toolkit][nvct] installed.
#### OpenVINO

View File

@@ -66,7 +66,7 @@ The provided file is just a starting point. There are a ton of ways to configure
After bringing down the containers with `docker compose down` and back up with `docker compose up -d`, a Prometheus instance will now collect metrics from the immich server and microservices containers. Note that we didn't need to expose any new ports for these containers - the communication is handled in the internal Docker network.
:::note
To see exactly what metrics are made available, you can additionally add `8081:8081` to the server container's ports and `8082:8081` to the microservices container's ports. Visiting the `/metrics` endpoint for these services will show the same raw data that Prometheus collects.
To see exactly what metrics are made available, you can additionally add `8081:8081` to the server container's ports and `8082:8082` to the microservices container's ports. Visiting the `/metrics` endpoint for these services will show the same raw data that Prometheus collects.
:::
### Usage

View File

@@ -7,29 +7,30 @@ Immich uses Postgres as its search database for both metadata and smart search.
Smart search is powered by the [pgvecto.rs](https://github.com/tensorchord/pgvecto.rs) extension, utilizing machine learning models like [CLIP](https://openai.com/research/clip) to provide relevant search results. This allows for freeform searches without requiring specific keywords in the image or video metadata.
Archived photos are not included in search results by default. To include them, mark the checkbox in [advanced search filters](/docs/features/smart-search#advanced-search-filters).
:::tip Alternative CLIP Models
More powerful models can be used for more accurate search results. For more information, see the related [FAQ](/docs/FAQ#can-i-use-a-custom-clip-model).
:::
:::info
Smart Search is currently limited to 5,000 results for a single search on the web.
:::
## Advanced Search Filters
In addition, Immich offers advanced search functionality, allowing you to find specific content using customizable search filters. These filters include location, one or more faces, specific albums, and more. You can try out the search filters on the [Demo site](https://demo.immich.app).
Smart search features include:
The filters smart search allows you to search by include:
- Search for one or more faces (with or without context search).
- Search by Country or State or City or by all three.
- Search by camera make and model.
- Search by date range.
- Search by file name.
- Search by media types: image, video or all (**Note:** Image includes live images).
- Search by condition: not in any album or archive or Favorite or all conditions.
- People
- Location
- Country
- State
- City
- Camera
- Make
- Model
- Date range
- File name or extension
- Media type
- Image (including live/motion photos)
- Video
- All
- Condition
- Not in any album
- Archived
- Favorited
<Tabs>
<TabItem value="Computer" label="Computer" default>
@@ -47,3 +48,27 @@ Some search examples:
</TabItem>
</Tabs>
## Configuration
Navigating to `Administration > Settings > Machine Learning Settings > Smart Search` will show the options available.
### CLIP model
More powerful models can be used for more accurate search results, but are slower and can require more server resources. Check out the models [here][huggingface-clip] for more options!
[Multilingual models][huggingface-multilingual-clip] are also available so users can search in their native language. These models support over 100 languages; the `nllb` models in particular support 200.
:::note
Multilingual models are much slower and larger and perform slightly worse for English than English-only models. For this reason, only use them if you actually intend to search in a language besides English.
As a special case, the `ViT-H-14-quickgelu__dfn5b` and `ViT-H-14-378-quickgelu__dfn5b` models are excellent at many European languages despite not specifically being multilingual. They're very intensive regardless, however - especially the latter.
:::
Once you've chosen a model, change this setting to the name of the model you chose. Be sure to re-run Smart Search on all assets after this change.
:::note
Feel free to make a feature request if there's a model you want to use that we don't currently support.
:::
[huggingface-clip]: https://huggingface.co/collections/immich-app/clip-654eaefb077425890874cd07
[huggingface-multilingual-clip]: https://huggingface.co/collections/immich-app/multilingual-clip-654eb08c2382f591eeb8c2a7

View File

@@ -13,14 +13,14 @@ In our `.env` file, we will define variables that will help us in the future whe
# Custom location where your uploaded, thumbnails, and transcoded video files are stored
- UPLOAD_LOCATION=./library
+ UPLOAD_LOCATION=/custom/location/on/your/system/immich/immich_files
+ THUMB_LOCATION=/custom/location/on/your/system/immich/thumbs
+ ENCODED_VIDEO_LOCATION=/custom/location/on/your/system/immich/encoded-video
+ PROFILE_LOCATION=/custom/location/on/your/system/immich/profile
+ UPLOAD_LOCATION=/custom/path/immich/immich_files
+ THUMB_LOCATION=/custom/path/immich/thumbs
+ ENCODED_VIDEO_LOCATION=/custom/path/immich/encoded-video
+ PROFILE_LOCATION=/custom/path/immich/profile
...
```
After defining the locations for these files, we will edit the `docker-compose.yml` file accordingly and add the new variables to the `immich-server` and `immich-microservices` containers.
After defining the locations for these files, we will edit the `docker-compose.yml` file accordingly and add the new variables to the `immich-server` container.
```diff title="docker-compose.yml"
services:
@@ -29,16 +29,6 @@ services:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
+ - ${THUMB_LOCATION}:/usr/src/app/upload/thumbs
+ - ${ENCODED_VIDEO_LOCATION}:/usr/src/app/upload/encoded-video
+ - ${PROFILE_LOCATION}:/usr/src/app/upload/profile
- /etc/localtime:/etc/localtime:ro
...
immich-microservices:
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
+ - ${THUMB_LOCATION}:/usr/src/app/upload/thumbs
+ - ${ENCODED_VIDEO_LOCATION}:/usr/src/app/upload/encoded-video
+ - ${PROFILE_LOCATION}:/usr/src/app/upload/profile
- /etc/localtime:/etc/localtime:ro
```
@@ -46,7 +36,6 @@ services:
Restart Immich to register the changes.
```
docker compose down
docker compose up -d
```

View File

@@ -1,8 +1,22 @@
# Create Custom Map Styles for Immich Using Maptiler
# Custom Map Styles
You may decide that you'd like to modify the style document which is used to draw the maps in Immich. This can be done easily using Maptiler, if you do not want to write an entire JSON document by hand.
You may decide that you'd like to modify the style document which is used to
draw the maps in Immich. In addition to visual customization, this also allows
you to pick your own map tile provider instead of the default one. The default
`style.json` for [light theme](https://github.com/immich-app/immich/tree/main/server/resources/style-light.json)
and [dark theme](https://github.com/immich-app/immich/blob/main/server/resources/style-dark.json)
can be used as a basis for creating your own style.
## Steps
There are several sources for already-made `style.json` map themes, as well as
online generators you can use.
1. In **Immich**, navigate to **Administration --> Settings --> Map & GPS Settings** and expand the **Map Settings** subsection.
2. Paste the link to your JSON style in either the **Light Style** or **Dark Style**. (You can add different styles which will help make the map style more appropriate depending on whether you set **Immich** to Light or Dark mode.)
3. Save your selections. Reload the map, and enjoy your custom map style!
## Use Maptiler to build a custom style
Customizing the map style can be done easily using Maptiler, if you do not want to write an entire JSON document by hand.
1. Create a free account at https://cloud.maptiler.com
2. Once logged in, you can either create a brand new map by clicking on **New Map**, selecting a starter map, and then clicking **Customize**, OR by selecting a **Standard Map** and customizing it from there.
@@ -11,6 +25,3 @@ You may decide that you'd like to modify the style document which is used to dra
5. Next, **Publish** your style using the **Publish** button at the top right. This will deploy it to production, which means it is able to be exposed over the Internet. Maptiler will present an interactive side-by-side map with the original and your changes prior to publication.<br/>![Maptiler Publication Settings](img/immich_map_styles_publish.png)
6. Maptiler will warn you that changing the map will change it across all apps using the map. Since no apps are using the map yet, this is okay.
7. Clicking on the name of your new map at the top left will bring you to the item's **details** page. From here, copy the link to the JSON style under **Use vector style**. This link will automatically contain your personal API key to Maptiler.
8. In **Immich**, navigate to **Administration --> Settings --> Map & GPS Settings** and expand the **Map Settings** subsection.
9. Paste the link to your JSON style in either the **Light Style** or **Dark Style**. (You can add different styles which will help make the map style more appropriate depending on whether you set **Immich** to Light or Dark mode.
10. Save your selections. Reload the map, and enjoy your custom map style!

View File

@@ -5,7 +5,7 @@ Keep in mind that mucking around in the database might set the moon on fire. Avo
:::
:::tip
Run `docker exec -it immich_postgres psql immich <DB_USERNAME>` to connect to the database via the container directly.
Run `docker exec -it immich_postgres psql --dbname=immich --username=<DB_USERNAME>` to connect to the database via the container directly.
(Replace `<DB_USERNAME>` with the value from your [`.env` file](/docs/install/environment-variables#database)).
:::
@@ -106,3 +106,9 @@ SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
```sql title="Delete person and unset it for the faces it was associated with"
DELETE FROM "person" WHERE "name" = 'PersonNameHere';
```
## Postgres internal
```sql title="Change DB_PASSWORD"
ALTER USER <DB_USERNAME> WITH ENCRYPTED PASSWORD 'newpasswordhere';
```

View File

@@ -6,36 +6,18 @@ in a directory on the same machine.
# Mount the directory into the containers.
Edit `docker-compose.yml` to add two new mount points in the section `immich-server:` under `volumes:`
Edit `docker-compose.yml` to add one or more new mount points in the section `immich-server:` under `volumes:`.
If you want Immich to be able to delete the images in the external library, remove `:ro` from the end of the mount point.
```diff
immich-server:
volumes:
+ - ${EXTERNAL_PATH}:/usr/src/app/external
- ${UPLOAD_LOCATION}:/usr/src/app/upload
+ - /home/user/photos1:/home/user/photos1:ro
+ - /mnt/photos2:/mnt/photos2:ro # you can delete this line if you only have one mount point, or you can add more lines if you have more than two
```
Edit `.env` to define `EXTERNAL_PATH`, substituting in the correct path for your computer:
```
EXTERNAL_PATH=<your-path-here>
```
On my computer, for example, I use this path:
```
EXTERNAL_PATH=/home/tenino/photos
```
:::info EXTERNAL_PATH design
The design choice to put the EXTERNAL_PATH into .env rather than put two copies of the absolute path in the yml file in order to make everything easier, so if you have two copies of the same path that have to be kept in sync, then someday later when you move the data, update only one of the paths, without everything will break mysteriously.
:::
Restart Immich.
```
docker compose down
docker compose up -d
```
Restart Immich by running `docker compose up -d`.
# Create the library

View File

@@ -4,7 +4,7 @@ This page gives a few pointers on how to access your Immich instance from outsid
You can read the [full discussion in Discord](https://discord.com/channels/979116623879368755/1122615710846308484)
:::danger
Never forward port 2283 directly to the internet without additional configuration. This will expose the web interface via http to the internet, making you succeptible to [man in the middle](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) attacks.
Never forward port 2283 directly to the internet without additional configuration. This will expose the web interface via http to the internet, making you susceptible to [man in the middle](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) attacks.
:::
## Option 1: VPN to home network

View File

@@ -4,14 +4,11 @@ To alleviate [performance issues on low-memory systems](/docs/FAQ.mdx#why-is-imm
- Set the URL in Machine Learning Settings on the Admin Settings page to point to the designated ML system, e.g. `http://workstation:3003`.
- Copy the following `docker-compose.yml` to your ML system.
- If using [hardware acceleration](/docs/features/ml-hardware-acceleration), the [hwaccel.ml.yml](https://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml) file also needs to be added
- Start the container by running `docker compose up -d`.
:::info
Starting with version v1.93.0 face detection work and face recognize were split. From now on face detection is done in the immich_machine_learning container, but facial recognition is done in the `microservices` worker.
:::
:::note
The [hwaccel.ml.yml](https://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml) file also needs to be in the same folder if trying to use [hardware acceleration](/docs/features/ml-hardware-acceleration).
Smart Search and Face Detection will use this feature, but Facial Recognition is handled in the server.
:::
```yaml
@@ -37,3 +34,7 @@ volumes:
```
Please note that version mismatches between both hosts may cause instabilities and bugs, so make sure to always perform updates together.
:::caution
As an internal service, the machine learning container has no security measures whatsoever. Please be mindful of where it's deployed and who can access it.
:::

View File

@@ -56,7 +56,8 @@ Optionally, you can enable hardware acceleration for machine learning and transc
- Populate custom database information if necessary.
- Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets.
- Consider changing `DB_PASSWORD` to something randomly generated
- Consider changing `DB_PASSWORD` to a custom value. Postgres is not publically 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`.
### Step 3 - Start the containers

View File

@@ -38,21 +38,23 @@ Regardless of filesystem, it is not recommended to use a network share for your
## General
| Variable | Description | Default | Containers | Workers |
| :---------------------------------- | :---------------------------------------------- | :--------------------------: | :----------------------- | :----------------- |
| `TZ` | Timezone | | server | microservices |
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
| `IMMICH_LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
| `IMMICH_MEDIA_LOCATION` | Media Location | `./upload`<sup>\*1</sup> | server | api, microservices |
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
| `IMMICH_WEB_ROOT` | Path of root index.html | `/usr/src/app/www` | server | api |
| `IMMICH_REVERSE_GEOCODING_ROOT` | Path of reverse geocoding dump directory | `/usr/src/resources` | server | microservices |
| `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 | |
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices |
| Variable | Description | Default | Containers | Workers |
| :---------------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- |
| `TZ` | Timezone | | server | microservices |
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
| `IMMICH_LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
| `IMMICH_MEDIA_LOCATION` | Media Location inside the container ⚠️**You probably shouldn't set this**<sup>\*1</sup>⚠️ | `./upload`<sup>\*2</sup> | server | api, microservices |
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
| `CPU_CORES` | Amount 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_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_TRUSTED_PROXIES` | List of comma separated IPs set as trusted proxies | | server | api |
\*1: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`.
\*1: 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: 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.
:::tip
@@ -157,18 +159,21 @@ Redis (Sentinel) URL example JSON before encoding:
## Machine Learning
| Variable | Description | Default | Containers |
| :----------------------------------------------- | :------------------------------------------------------------------- | :-----------------: | :--------------- |
| `MACHINE_LEARNING_MODEL_TTL` | Inactivity time (s) before a model is unloaded (disabled if \<= 0) | `300` | machine learning |
| `MACHINE_LEARNING_MODEL_TTL_POLL_S` | Interval (s) between checks for the model TTL (disabled if \<= 0) | `10` | machine learning |
| `MACHINE_LEARNING_CACHE_FOLDER` | Directory where models are downloaded | `/cache` | machine learning |
| `MACHINE_LEARNING_REQUEST_THREADS`<sup>\*1</sup> | Thread count of the request thread pool (disabled if \<= 0) | number of CPU cores | machine learning |
| `MACHINE_LEARNING_MODEL_INTER_OP_THREADS` | Number of parallel model operations | `1` | machine learning |
| `MACHINE_LEARNING_MODEL_INTRA_OP_THREADS` | Number of threads for each model operation | `2` | machine learning |
| `MACHINE_LEARNING_WORKERS`<sup>\*2</sup> | Number of worker processes to spawn | `1` | machine learning |
| `MACHINE_LEARNING_WORKER_TIMEOUT` | Maximum time (s) of unresponsiveness before a worker is killed | `120` | machine learning |
| `MACHINE_LEARNING_PRELOAD__CLIP` | Name of a CLIP model to be preloaded and kept in cache | | machine learning |
| `MACHINE_LEARNING_PRELOAD__FACIAL_RECOGNITION` | Name of a facial recognition model to be preloaded and kept in cache | | machine learning |
| Variable | Description | Default | Containers |
| :----------------------------------------------- | :-------------------------------------------------------------------------------------------------- | :-----------------------------------: | :--------------- |
| `MACHINE_LEARNING_MODEL_TTL` | Inactivity time (s) before a model is unloaded (disabled if \<= 0) | `300` | machine learning |
| `MACHINE_LEARNING_MODEL_TTL_POLL_S` | Interval (s) between checks for the model TTL (disabled if \<= 0) | `10` | machine learning |
| `MACHINE_LEARNING_CACHE_FOLDER` | Directory where models are downloaded | `/cache` | machine learning |
| `MACHINE_LEARNING_REQUEST_THREADS`<sup>\*1</sup> | Thread count of the request thread pool (disabled if \<= 0) | number of CPU cores | machine learning |
| `MACHINE_LEARNING_MODEL_INTER_OP_THREADS` | Number of parallel model operations | `1` | machine learning |
| `MACHINE_LEARNING_MODEL_INTRA_OP_THREADS` | Number of threads for each model operation | `2` | machine learning |
| `MACHINE_LEARNING_WORKERS`<sup>\*2</sup> | Number of worker processes to spawn | `1` | machine learning |
| `MACHINE_LEARNING_WORKER_TIMEOUT` | Maximum time (s) of unresponsiveness before a worker is killed | `120` (`300` if using OpenVINO image) | machine learning |
| `MACHINE_LEARNING_PRELOAD__CLIP` | Name of a CLIP model to be preloaded and kept in cache | | machine learning |
| `MACHINE_LEARNING_PRELOAD__FACIAL_RECOGNITION` | Name of a facial recognition model to be preloaded and kept in cache | | machine learning |
| `MACHINE_LEARNING_ANN` | Enable ARM-NN hardware acceleration if supported | `True` | machine learning |
| `MACHINE_LEARNING_ANN_FP16_TURBO` | Execute operations in FP16 precision: increasing speed, reducing precision (applies only to ARM-NN) | `False` | machine learning |
| `MACHINE_LEARNING_ANN_TUNING_LEVEL` | ARM-NN GPU tuning level (1: rapid, 2: normal, 3: exhaustive) | `2` | 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.

View File

@@ -8,6 +8,10 @@ sidebar_position: 20
This method is experimental and not currently recommended for production use. For production, please refer to installing with [Docker Compose](/docs/install/docker-compose.mdx).
:::
:::note
The install script only supports Linux operating systems and requires Docker to be already installed on the system.
:::
In the shell, from a directory of your choice, run the following command:
```bash

View File

@@ -27,7 +27,7 @@ For more information about setting up the community image see [here](https://git
:::info
- Guide was written using Unraid v6.12.10
- Guide was written using Unraid v6.12.10.
- Requires you to have installed the plugin: [Docker Compose Manager](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/)
- An Unraid share created for your images
- There has been a [report](https://forums.unraid.net/topic/130006-errortraps-traps-node27707-trap-invalid-opcode-ip14fcfc8d03c0-sp7fff32889dd8-more/#comment-1189395) of this not working if your Unraid server doesn't support AVX _(e.g. using a T610)_
@@ -46,7 +46,8 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
/>
3. Select the cog ⚙️ next to Immich then click "**Edit Stack**"
4. Click "**Compose File**" and then paste the entire contents of the [Immich Docker Compose](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml) file into the Unraid editor. Remove any text that may be in the text area by default.
4. Click "**Compose File**" and then paste the entire contents of the [Immich Docker Compose](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml) file into the Unraid editor. Remove any text that may be in the text area by default. Note that Unraid v6.12.10 uses version 24.0.9 of the Docker Engine, which does not support healthcheck `start_interval` as defined in the `database` service of the Docker compose file (version 25 or higher is needed). This parameter defines an initial waiting period before starting health checks, to give the container time to start up. Commenting out the `start_interval` and `start_period` parameters will allow the containers to start up normally. The only downside to this is that the database container will not receive an initial health check until `interval` time has passed.
<details >
<summary>Using an existing Postgres container? Click me! Otherwise proceed to step 5.</summary>
<ul>
@@ -70,6 +71,7 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
/>
</ul>
</details>
5. Click "**Save Changes**", you will be promoted to edit stack UI labels, just leave this blank and click "**Ok**"
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following:

View File

@@ -13,4 +13,4 @@ Running into an issue or have a question? Try the following:
[github-issues]: https://github.com/immich-app/immich/issues
[github-releases]: https://github.com/immich-app/immich/releases
[discord-link]: https://discord.com/invite/D8JsnBEuKb
[discord-link]: https://discord.immich.app

View File

@@ -5,21 +5,21 @@ sidebar_position: 3
# Quick Start
Here is a quick, no-choices path to install Immich and take it for a test drive.
Once you've tried it, perhaps you'll use one of the many other ways
Once you've tried it, you might use one of the many other ways
to install and use it.
## Requirements
Check the [requirements page](/docs/install/requirements) to get started.
## Install and launch via Docker Compose
## Install and Launch via Docker Compose
Follow the [Docker Compose (Recommended)](/docs/install/docker-compose) instructions
to install the server.
- Where random passwords are required, `pwgen` is a handy utility.
- `UPLOAD_LOCATION` should be set to some new directory on the server
with free space.
with enough free space.
- You may ignore "Step 4 - Upgrading".
## Try the Web UI
@@ -48,26 +48,26 @@ import MobileAppLogin from '/docs/partials/_mobile-app-login.md';
In the mobile app, you should see the photo you uploaded from the web UI.
### Transfer Photos from your Mobile Device
### Transfer Photos from Your Mobile Device
import MobileAppBackup from '/docs/partials/_mobile-app-backup.md';
<MobileAppBackup />
Depending on how many photos are on your mobile device, this backup may
The backup time differs depending on how many photos are on your mobile device. Large uploads may
take quite a while.
You can select the Jobs tab to see Immich processing your photos.
You can select the **Jobs** tab to see Immich processing your photos.
<img src={require('/docs/guides/img/jobs-tab.png').default} title="Jobs tab" />
## Set up your backups
## Set up Your Backups
You may want to back up the content of your Immich instance
along with other parts of your server; be sure to read about
[database backup](/docs/administration/backup-and-restore).
## Where to go from here?
## Where to Go From Here
You may decide you'd like to install the server a different way;
the Install category on the left menu provides many options.

View File

@@ -4,11 +4,17 @@ sidebar_position: 5
# Support The Project
## Contributing
## Report issues
1. Testing - Using Immich and reporting bugs is a great way to help support the project. Found a bug? [Open an issue on GitHub][github-issue].
1. Translations - The Immich mobile app has been translated into [17 languages][github-langs] so far! To contribute with translations, email me at alex.tran1502@gmail.com or send me a message on discord.
1. Development - If you are a programmer or developer, take a look at Immich's [technology stack](/docs/developer/architecture.mdx) and consider fixing bugs or building new features. The team and I are always looking for new contributors. For information about how to contribute as a developer, see the [Developer](/docs/developer/architecture.mdx) section.
By far the easiest way to help make Immich better it to use it and report issues and bugs. Found a bug? [Open an issue on GitHub][github-issue].
## Translations
Support the project by localizing on [Weblate](https://hosted.weblate.org/projects/immich/immich/). For more information, see the [Translations](/docs/developer/translations) section.
## Development
If you are a programmer or developer, take a look at Immich's [technology stack](/docs/developer/architecture.mdx) and consider fixing bugs or building new features. The team and I are always looking for new contributors. For information about how to contribute as a developer, see the [Developer](/docs/developer/architecture.mdx) section.
[github-issue]: https://github.com/immich-app/immich/issues/new/choose
[github-langs]: https://github.com/immich-app/immich/tree/main/mobile/assets/i18n

View File

@@ -92,6 +92,7 @@ const config = {
alt: 'Immich Logo',
src: 'img/immich-logo-inline-light.png',
srcDark: 'img/immich-logo-inline-dark.png',
className: 'rounded-none',
},
items: [
{
@@ -124,7 +125,7 @@ const config = {
position: 'right',
},
{
href: 'https://discord.gg/D8JsnBEuKb',
href: 'https://discord.immich.app',
label: 'Discord',
position: 'right',
},
@@ -144,28 +145,36 @@ const config = {
label: 'Installation',
to: '/docs/install/requirements',
},
{
label: 'Contributing',
to: '/docs/overview/support-the-project',
},
{
label: 'Privacy Policy',
to: '/privacy-policy',
},
],
},
{
title: 'Community',
title: 'Documentation',
items: [
{
label: 'Discord',
href: 'https://discord.com/invite/D8JsnBEuKb',
label: 'Roadmap',
to: '/roadmap',
},
{
label: 'Reddit',
href: 'https://www.reddit.com/r/immich/',
label: 'API',
to: '/docs/api',
},
{
label: 'Cursed Knowledge',
to: '/cursed-knowledge',
},
],
},
{
title: 'Links',
items: [
// {
// label: "Blog",
// to: "/blog",
// },
{
label: 'GitHub',
href: 'https://github.com/immich-app/immich',
@@ -174,6 +183,14 @@ const config = {
label: 'YouTube',
href: 'https://www.youtube.com/@immich-app',
},
{
label: 'Discord',
href: 'https://discord.immich.app',
},
{
label: 'Reddit',
href: 'https://www.reddit.com/r/immich/',
},
],
},
],

463
docs/package-lock.json generated
View File

@@ -2155,9 +2155,10 @@
}
},
"node_modules/@docusaurus/core": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.3.2.tgz",
"integrity": "sha512-PzKMydKI3IU1LmeZQDi+ut5RSuilbXnA8QdowGeJEgU8EJjmx3rBHNT1LxQxOVqNEwpWi/csLwd9bn7rUjggPA==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.4.0.tgz",
"integrity": "sha512-g+0wwmN2UJsBqy2fQRQ6fhXruoEa62JDeEa5d8IdTJlMoaDaEDfHh7WjwGRn4opuTQWpjAwP/fbcgyHKlE+64w==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.23.3",
"@babel/generator": "^7.23.3",
@@ -2169,12 +2170,12 @@
"@babel/runtime": "^7.22.6",
"@babel/runtime-corejs3": "^7.22.6",
"@babel/traverse": "^7.22.8",
"@docusaurus/cssnano-preset": "3.3.2",
"@docusaurus/logger": "3.3.2",
"@docusaurus/mdx-loader": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-common": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/cssnano-preset": "3.4.0",
"@docusaurus/logger": "3.4.0",
"@docusaurus/mdx-loader": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-common": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"autoprefixer": "^10.4.14",
"babel-loader": "^9.1.3",
"babel-plugin-dynamic-import-node": "^2.3.3",
@@ -2240,9 +2241,10 @@
}
},
"node_modules/@docusaurus/cssnano-preset": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.3.2.tgz",
"integrity": "sha512-+5+epLk/Rp4vFML4zmyTATNc3Is+buMAL6dNjrMWahdJCJlMWMPd/8YfU+2PA57t8mlSbhLJ7vAZVy54cd1vRQ==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.4.0.tgz",
"integrity": "sha512-qwLFSz6v/pZHy/UP32IrprmH5ORce86BGtN0eBtG75PpzQJAzp9gefspox+s8IEOr0oZKuQ/nhzZ3xwyc3jYJQ==",
"license": "MIT",
"dependencies": {
"cssnano-preset-advanced": "^6.1.2",
"postcss": "^8.4.38",
@@ -2254,9 +2256,10 @@
}
},
"node_modules/@docusaurus/logger": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.3.2.tgz",
"integrity": "sha512-Ldu38GJ4P8g4guN7d7pyCOJ7qQugG7RVyaxrK8OnxuTlaImvQw33aDRwaX2eNmX8YK6v+//Z502F4sOZbHHCHQ==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.4.0.tgz",
"integrity": "sha512-bZwkX+9SJ8lB9kVRkXw+xvHYSMGG4bpYHKGXeXFvyVc79NMeeBSGgzd4TQLHH+DYeOJoCdl8flrFJVxlZ0wo/Q==",
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"tslib": "^2.6.0"
@@ -2266,13 +2269,14 @@
}
},
"node_modules/@docusaurus/mdx-loader": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.3.2.tgz",
"integrity": "sha512-AFRxj/aOk3/mfYDPxE3wTbrjeayVRvNSZP7mgMuUlrb2UlPRbSVAFX1k2RbgAJrnTSwMgb92m2BhJgYRfptN3g==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.4.0.tgz",
"integrity": "sha512-kSSbrrk4nTjf4d+wtBA9H+FGauf2gCax89kV8SUSJu3qaTdSIKdWERlngsiHaCFgZ7laTJ8a67UFf+xlFPtuTw==",
"license": "MIT",
"dependencies": {
"@docusaurus/logger": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/logger": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
@@ -2304,11 +2308,12 @@
}
},
"node_modules/@docusaurus/module-type-aliases": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.3.2.tgz",
"integrity": "sha512-b/XB0TBJah5yKb4LYuJT4buFvL0MGAb0+vJDrJtlYMguRtsEBkf2nWl5xP7h4Dlw6ol0hsHrCYzJ50kNIOEclw==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.4.0.tgz",
"integrity": "sha512-A1AyS8WF5Bkjnb8s+guTDuYmUiwJzNrtchebBHpc0gz0PyHJNMaybUlSrmJjHVcGrya0LKI4YcR3lBDQfXRYLw==",
"license": "MIT",
"dependencies": {
"@docusaurus/types": "3.3.2",
"@docusaurus/types": "3.4.0",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@@ -2322,17 +2327,18 @@
}
},
"node_modules/@docusaurus/plugin-content-blog": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.3.2.tgz",
"integrity": "sha512-fJU+dmqp231LnwDJv+BHVWft8pcUS2xVPZdeYH6/ibH1s2wQ/sLcmUrGWyIv/Gq9Ptj8XWjRPMghlxghuPPoxg==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.4.0.tgz",
"integrity": "sha512-vv6ZAj78ibR5Jh7XBUT4ndIjmlAxkijM3Sx5MAAzC1gyv0vupDQNhzuFg1USQmQVj3P5I6bquk12etPV3LJ+Xw==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/logger": "3.3.2",
"@docusaurus/mdx-loader": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-common": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/logger": "3.4.0",
"@docusaurus/mdx-loader": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-common": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"cheerio": "^1.0.0-rc.12",
"feed": "^4.2.2",
"fs-extra": "^11.1.1",
@@ -2353,18 +2359,19 @@
}
},
"node_modules/@docusaurus/plugin-content-docs": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.3.2.tgz",
"integrity": "sha512-Dm1ri2VlGATTN3VGk1ZRqdRXWa1UlFubjaEL6JaxaK7IIFqN/Esjpl+Xw10R33loHcRww/H76VdEeYayaL76eg==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.4.0.tgz",
"integrity": "sha512-HkUCZffhBo7ocYheD9oZvMcDloRnGhBMOZRyVcAQRFmZPmNqSyISlXA1tQCIxW+r478fty97XXAGjNYzBjpCsg==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/logger": "3.3.2",
"@docusaurus/mdx-loader": "3.3.2",
"@docusaurus/module-type-aliases": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-common": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/logger": "3.4.0",
"@docusaurus/mdx-loader": "3.4.0",
"@docusaurus/module-type-aliases": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-common": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"@types/react-router-config": "^5.0.7",
"combine-promises": "^1.1.0",
"fs-extra": "^11.1.1",
@@ -2383,15 +2390,16 @@
}
},
"node_modules/@docusaurus/plugin-content-pages": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.3.2.tgz",
"integrity": "sha512-EKc9fQn5H2+OcGER8x1aR+7URtAGWySUgULfqE/M14+rIisdrBstuEZ4lUPDRrSIexOVClML82h2fDS+GSb8Ew==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.4.0.tgz",
"integrity": "sha512-h2+VN/0JjpR8fIkDEAoadNjfR3oLzB+v1qSXbIAKjQ46JAHx3X22n9nqS+BWSQnTnp1AjkjSvZyJMekmcwxzxg==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/mdx-loader": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/mdx-loader": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"fs-extra": "^11.1.1",
"tslib": "^2.6.0",
"webpack": "^5.88.1"
@@ -2405,13 +2413,14 @@
}
},
"node_modules/@docusaurus/plugin-debug": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.3.2.tgz",
"integrity": "sha512-oBIBmwtaB+YS0XlmZ3gCO+cMbsGvIYuAKkAopoCh0arVjtlyPbejzPrHuCoRHB9G7abjNZw7zoONOR8+8LM5+Q==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.4.0.tgz",
"integrity": "sha512-uV7FDUNXGyDSD3PwUaf5YijX91T5/H9SX4ErEcshzwgzWwBtK37nUWPU3ZLJfeTavX3fycTOqk9TglpOLaWkCg==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils": "3.4.0",
"fs-extra": "^11.1.1",
"react-json-view-lite": "^1.2.0",
"tslib": "^2.6.0"
@@ -2425,13 +2434,14 @@
}
},
"node_modules/@docusaurus/plugin-google-analytics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.3.2.tgz",
"integrity": "sha512-jXhrEIhYPSClMBK6/IA8qf1/FBoxqGXZvg7EuBax9HaK9+kL3L0TJIlatd8jQJOMtds8mKw806TOCc3rtEad1A==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.4.0.tgz",
"integrity": "sha512-mCArluxEGi3cmYHqsgpGGt3IyLCrFBxPsxNZ56Mpur0xSlInnIHoeLDH7FvVVcPJRPSQ9/MfRqLsainRw+BojA==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"tslib": "^2.6.0"
},
"engines": {
@@ -2443,13 +2453,14 @@
}
},
"node_modules/@docusaurus/plugin-google-gtag": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.3.2.tgz",
"integrity": "sha512-vcrKOHGbIDjVnNMrfbNpRQR1x6Jvcrb48kVzpBAOsKbj9rXZm/idjVAXRaewwobHdOrJkfWS/UJoxzK8wyLRBQ==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.4.0.tgz",
"integrity": "sha512-Dsgg6PLAqzZw5wZ4QjUYc8Z2KqJqXxHxq3vIoyoBWiLEEfigIs7wHR+oiWUQy3Zk9MIk6JTYj7tMoQU0Jm3nqA==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"@types/gtag.js": "^0.0.12",
"tslib": "^2.6.0"
},
@@ -2462,13 +2473,14 @@
}
},
"node_modules/@docusaurus/plugin-google-tag-manager": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.3.2.tgz",
"integrity": "sha512-ldkR58Fdeks0vC+HQ+L+bGFSJsotQsipXD+iKXQFvkOfmPIV6QbHRd7IIcm5b6UtwOiK33PylNS++gjyLUmaGw==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.4.0.tgz",
"integrity": "sha512-O9tX1BTwxIhgXpOLpFDueYA9DWk69WCbDRrjYoMQtFHSkTyE7RhNgyjSPREUWJb9i+YUg3OrsvrBYRl64FCPCQ==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"tslib": "^2.6.0"
},
"engines": {
@@ -2480,16 +2492,17 @@
}
},
"node_modules/@docusaurus/plugin-sitemap": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.3.2.tgz",
"integrity": "sha512-/ZI1+bwZBhAgC30inBsHe3qY9LOZS+79fRGkNdTcGHRMcdAp6Vw2pCd1gzlxd/xU+HXsNP6cLmTOrggmRp3Ujg==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.4.0.tgz",
"integrity": "sha512-+0VDvx9SmNrFNgwPoeoCha+tRoAjopwT0+pYO1xAbyLcewXSemq+eLxEa46Q1/aoOaJQ0qqHELuQM7iS2gp33Q==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/logger": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-common": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/logger": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-common": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"fs-extra": "^11.1.1",
"sitemap": "^7.1.1",
"tslib": "^2.6.0"
@@ -2503,23 +2516,24 @@
}
},
"node_modules/@docusaurus/preset-classic": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.3.2.tgz",
"integrity": "sha512-1SDS7YIUN1Pg3BmD6TOTjhB7RSBHJRpgIRKx9TpxqyDrJ92sqtZhomDc6UYoMMLQNF2wHFZZVGFjxJhw2VpL+Q==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.4.0.tgz",
"integrity": "sha512-Ohj6KB7siKqZaQhNJVMBBUzT3Nnp6eTKqO+FXO3qu/n1hJl3YLwVKTWBg28LF7MWrKu46UuYavwMRxud0VyqHg==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/plugin-content-blog": "3.3.2",
"@docusaurus/plugin-content-docs": "3.3.2",
"@docusaurus/plugin-content-pages": "3.3.2",
"@docusaurus/plugin-debug": "3.3.2",
"@docusaurus/plugin-google-analytics": "3.3.2",
"@docusaurus/plugin-google-gtag": "3.3.2",
"@docusaurus/plugin-google-tag-manager": "3.3.2",
"@docusaurus/plugin-sitemap": "3.3.2",
"@docusaurus/theme-classic": "3.3.2",
"@docusaurus/theme-common": "3.3.2",
"@docusaurus/theme-search-algolia": "3.3.2",
"@docusaurus/types": "3.3.2"
"@docusaurus/core": "3.4.0",
"@docusaurus/plugin-content-blog": "3.4.0",
"@docusaurus/plugin-content-docs": "3.4.0",
"@docusaurus/plugin-content-pages": "3.4.0",
"@docusaurus/plugin-debug": "3.4.0",
"@docusaurus/plugin-google-analytics": "3.4.0",
"@docusaurus/plugin-google-gtag": "3.4.0",
"@docusaurus/plugin-google-tag-manager": "3.4.0",
"@docusaurus/plugin-sitemap": "3.4.0",
"@docusaurus/theme-classic": "3.4.0",
"@docusaurus/theme-common": "3.4.0",
"@docusaurus/theme-search-algolia": "3.4.0",
"@docusaurus/types": "3.4.0"
},
"engines": {
"node": ">=18.0"
@@ -2530,22 +2544,23 @@
}
},
"node_modules/@docusaurus/theme-classic": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.3.2.tgz",
"integrity": "sha512-gepHFcsluIkPb4Im9ukkiO4lXrai671wzS3cKQkY9BXQgdVwsdPf/KS0Vs4Xlb0F10fTz+T3gNjkxNEgSN9M0A==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.4.0.tgz",
"integrity": "sha512-0IPtmxsBYv2adr1GnZRdMkEQt1YW6tpzrUPj02YxNpvJ5+ju4E13J5tB4nfdaen/tfR1hmpSPlTFPvTf4kwy8Q==",
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.3.2",
"@docusaurus/mdx-loader": "3.3.2",
"@docusaurus/module-type-aliases": "3.3.2",
"@docusaurus/plugin-content-blog": "3.3.2",
"@docusaurus/plugin-content-docs": "3.3.2",
"@docusaurus/plugin-content-pages": "3.3.2",
"@docusaurus/theme-common": "3.3.2",
"@docusaurus/theme-translations": "3.3.2",
"@docusaurus/types": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-common": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/mdx-loader": "3.4.0",
"@docusaurus/module-type-aliases": "3.4.0",
"@docusaurus/plugin-content-blog": "3.4.0",
"@docusaurus/plugin-content-docs": "3.4.0",
"@docusaurus/plugin-content-pages": "3.4.0",
"@docusaurus/theme-common": "3.4.0",
"@docusaurus/theme-translations": "3.4.0",
"@docusaurus/types": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-common": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"copy-text-to-clipboard": "^3.2.0",
@@ -2569,17 +2584,18 @@
}
},
"node_modules/@docusaurus/theme-common": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.3.2.tgz",
"integrity": "sha512-kXqSaL/sQqo4uAMQ4fHnvRZrH45Xz2OdJ3ABXDS7YVGPSDTBC8cLebFrRR4YF9EowUHto1UC/EIklJZQMG/usA==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.4.0.tgz",
"integrity": "sha512-0A27alXuv7ZdCg28oPE8nH/Iz73/IUejVaCazqu9elS4ypjiLhK3KfzdSQBnL/g7YfHSlymZKdiOHEo8fJ0qMA==",
"license": "MIT",
"dependencies": {
"@docusaurus/mdx-loader": "3.3.2",
"@docusaurus/module-type-aliases": "3.3.2",
"@docusaurus/plugin-content-blog": "3.3.2",
"@docusaurus/plugin-content-docs": "3.3.2",
"@docusaurus/plugin-content-pages": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-common": "3.3.2",
"@docusaurus/mdx-loader": "3.4.0",
"@docusaurus/module-type-aliases": "3.4.0",
"@docusaurus/plugin-content-blog": "3.4.0",
"@docusaurus/plugin-content-docs": "3.4.0",
"@docusaurus/plugin-content-pages": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-common": "3.4.0",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@@ -2598,18 +2614,19 @@
}
},
"node_modules/@docusaurus/theme-search-algolia": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.3.2.tgz",
"integrity": "sha512-qLkfCl29VNBnF1MWiL9IyOQaHxUvicZp69hISyq/xMsNvFKHFOaOfk9xezYod2Q9xx3xxUh9t/QPigIei2tX4w==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.4.0.tgz",
"integrity": "sha512-aiHFx7OCw4Wck1z6IoShVdUWIjntC8FHCw9c5dR8r3q4Ynh+zkS8y2eFFunN/DL6RXPzpnvKCg3vhLQYJDmT9Q==",
"license": "MIT",
"dependencies": {
"@docsearch/react": "^3.5.2",
"@docusaurus/core": "3.3.2",
"@docusaurus/logger": "3.3.2",
"@docusaurus/plugin-content-docs": "3.3.2",
"@docusaurus/theme-common": "3.3.2",
"@docusaurus/theme-translations": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-validation": "3.3.2",
"@docusaurus/core": "3.4.0",
"@docusaurus/logger": "3.4.0",
"@docusaurus/plugin-content-docs": "3.4.0",
"@docusaurus/theme-common": "3.4.0",
"@docusaurus/theme-translations": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-validation": "3.4.0",
"algoliasearch": "^4.18.0",
"algoliasearch-helper": "^3.13.3",
"clsx": "^2.0.0",
@@ -2628,9 +2645,10 @@
}
},
"node_modules/@docusaurus/theme-translations": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.3.2.tgz",
"integrity": "sha512-bPuiUG7Z8sNpGuTdGnmKl/oIPeTwKr0AXLGu9KaP6+UFfRZiyWbWE87ti97RrevB2ffojEdvchNujparR3jEZQ==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.4.0.tgz",
"integrity": "sha512-zSxCSpmQCCdQU5Q4CnX/ID8CSUUI3fvmq4hU/GNP/XoAWtXo9SAVnM3TzpU8Gb//H3WCsT8mJcTfyOk3d9ftNg==",
"license": "MIT",
"dependencies": {
"fs-extra": "^11.1.1",
"tslib": "^2.6.0"
@@ -2640,9 +2658,10 @@
}
},
"node_modules/@docusaurus/types": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.3.2.tgz",
"integrity": "sha512-5p201S7AZhliRxTU7uMKtSsoC8mgPA9bs9b5NQg1IRdRxJfflursXNVsgc3PcMqiUTul/v1s3k3rXXFlRE890w==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.4.0.tgz",
"integrity": "sha512-4jcDO8kXi5Cf9TcyikB/yKmz14f2RZ2qTRerbHAsS+5InE9ZgSLBNLsewtFTcTOXSVcbU3FoGOzcNWAmU1TR0A==",
"license": "MIT",
"dependencies": {
"@mdx-js/mdx": "^3.0.0",
"@types/history": "^4.7.11",
@@ -2660,12 +2679,13 @@
}
},
"node_modules/@docusaurus/utils": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.3.2.tgz",
"integrity": "sha512-f4YMnBVymtkSxONv4Y8js3Gez9IgHX+Lcg6YRMOjVbq8sgCcdYK1lf6SObAuz5qB/mxiSK7tW0M9aaiIaUSUJg==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.4.0.tgz",
"integrity": "sha512-fRwnu3L3nnWaXOgs88BVBmG1yGjcQqZNHG+vInhEa2Sz2oQB+ZjbEMO5Rh9ePFpZ0YDiDUhpaVjwmS+AU2F14g==",
"license": "MIT",
"dependencies": {
"@docusaurus/logger": "3.3.2",
"@docusaurus/utils-common": "3.3.2",
"@docusaurus/logger": "3.4.0",
"@docusaurus/utils-common": "3.4.0",
"@svgr/webpack": "^8.1.0",
"escape-string-regexp": "^4.0.0",
"file-loader": "^6.2.0",
@@ -2682,6 +2702,7 @@
"shelljs": "^0.8.5",
"tslib": "^2.6.0",
"url-loader": "^4.1.1",
"utility-types": "^3.10.0",
"webpack": "^5.88.1"
},
"engines": {
@@ -2697,9 +2718,10 @@
}
},
"node_modules/@docusaurus/utils-common": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.3.2.tgz",
"integrity": "sha512-QWFTLEkPYsejJsLStgtmetMFIA3pM8EPexcZ4WZ7b++gO5jGVH7zsipREnCHzk6+eDgeaXfkR6UPaTt86bp8Og==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.4.0.tgz",
"integrity": "sha512-NVx54Wr4rCEKsjOH5QEVvxIqVvm+9kh7q8aYTU5WzUU9/Hctd6aTrcZ3G0Id4zYJ+AeaG5K5qHA4CY5Kcm2iyQ==",
"license": "MIT",
"dependencies": {
"tslib": "^2.6.0"
},
@@ -2716,15 +2738,18 @@
}
},
"node_modules/@docusaurus/utils-validation": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.3.2.tgz",
"integrity": "sha512-itDgFs5+cbW9REuC7NdXals4V6++KifgVMzoGOOOSIifBQw+8ULhy86u5e1lnptVL0sv8oAjq2alO7I40GR7pA==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.4.0.tgz",
"integrity": "sha512-hYQ9fM+AXYVTWxJOT1EuNaRnrR2WGpRdLDQG07O8UOpsvCPWUVOeo26Rbm0JWY2sGLfzAb+tvJ62yF+8F+TV0g==",
"license": "MIT",
"dependencies": {
"@docusaurus/logger": "3.3.2",
"@docusaurus/utils": "3.3.2",
"@docusaurus/utils-common": "3.3.2",
"@docusaurus/logger": "3.4.0",
"@docusaurus/utils": "3.4.0",
"@docusaurus/utils-common": "3.4.0",
"fs-extra": "^11.2.0",
"joi": "^17.9.2",
"js-yaml": "^4.1.0",
"lodash": "^4.17.21",
"tslib": "^2.6.0"
},
"engines": {
@@ -4212,9 +4237,9 @@
}
},
"node_modules/autoprefixer": {
"version": "10.4.19",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
"integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==",
"version": "10.4.20",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
"integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
"funding": [
{
"type": "opencollective",
@@ -4229,12 +4254,13 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"browserslist": "^4.23.0",
"caniuse-lite": "^1.0.30001599",
"browserslist": "^4.23.3",
"caniuse-lite": "^1.0.30001646",
"fraction.js": "^4.3.7",
"normalize-range": "^0.1.2",
"picocolors": "^1.0.0",
"picocolors": "^1.0.1",
"postcss-value-parser": "^4.2.0"
},
"bin": {
@@ -4506,9 +4532,9 @@
}
},
"node_modules/browserslist": {
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
"version": "4.23.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
"integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
"funding": [
{
"type": "opencollective",
@@ -4523,11 +4549,12 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"caniuse-lite": "^1.0.30001587",
"electron-to-chromium": "^1.4.668",
"node-releases": "^2.0.14",
"update-browserslist-db": "^1.0.13"
"caniuse-lite": "^1.0.30001646",
"electron-to-chromium": "^1.5.4",
"node-releases": "^2.0.18",
"update-browserslist-db": "^1.1.0"
},
"bin": {
"browserslist": "cli.js"
@@ -4674,9 +4701,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001614",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz",
"integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==",
"version": "1.0.30001651",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz",
"integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==",
"funding": [
{
"type": "opencollective",
@@ -4690,7 +4717,8 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
]
],
"license": "CC-BY-4.0"
},
"node_modules/ccount": {
"version": "2.0.1",
@@ -6317,9 +6345,10 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/electron-to-chromium": {
"version": "1.4.751",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz",
"integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw=="
"version": "1.5.6",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.6.tgz",
"integrity": "sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==",
"license": "ISC"
},
"node_modules/emoji-regex": {
"version": "9.2.2",
@@ -11933,9 +11962,10 @@
}
},
"node_modules/node-releases": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
"license": "MIT"
},
"node_modules/nopt": {
"version": "1.0.10",
@@ -12615,9 +12645,10 @@
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
"license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -12728,9 +12759,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.38",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
"integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
"version": "8.4.40",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz",
"integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==",
"funding": [
{
"type": "opencollective",
@@ -12745,9 +12776,10 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"picocolors": "^1.0.1",
"source-map-js": "^1.2.0"
},
"engines": {
@@ -13573,10 +13605,11 @@
}
},
"node_modules/prettier": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -13719,9 +13752,10 @@
}
},
"node_modules/qs": {
"version": "6.12.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
"integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.0.6"
},
@@ -15986,9 +16020,10 @@
}
},
"node_modules/tailwindcss": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
"integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.9.tgz",
"integrity": "sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==",
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -16025,6 +16060,7 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
},
@@ -16346,9 +16382,10 @@
}
},
"node_modules/typescript": {
"version": "5.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -16576,9 +16613,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.0.13",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
"integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
"funding": [
{
"type": "opencollective",
@@ -16593,9 +16630,10 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"escalade": "^3.1.1",
"picocolors": "^1.0.0"
"escalade": "^3.1.2",
"picocolors": "^1.0.1"
},
"bin": {
"update-browserslist-db": "cli.js"
@@ -16683,12 +16721,16 @@
}
},
"node_modules/url": {
"version": "0.11.3",
"resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz",
"integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==",
"version": "0.11.4",
"resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz",
"integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==",
"license": "MIT",
"dependencies": {
"punycode": "^1.4.1",
"qs": "^6.11.2"
"qs": "^6.12.3"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/url-loader": {
@@ -16752,7 +16794,8 @@
"node_modules/url/node_modules/punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
"license": "MIT"
},
"node_modules/util": {
"version": "0.10.4",

View File

@@ -56,6 +56,6 @@
"node": ">=20"
},
"volta": {
"node": "20.14.0"
"node": "20.16.0"
}
}

View File

@@ -38,6 +38,11 @@ const guides: CommunityGuidesProps[] = [
description: 'Import your Google Photos files into Immich and add your albums',
url: 'https://github.com/immich-app/immich/discussions/1340',
},
{
title: 'Access Immich with custom domain',
description: 'Access your local Immich installation over the internet using your own domain',
url: 'https://github.com/ppr88/immich-guides/blob/main/open-immich-custom-domain.md',
},
];
function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element {

View File

@@ -63,6 +63,11 @@ const projects: CommunityProjectProps[] = [
description: 'Powershell Module for the Immich API',
url: 'https://github.com/hanpq/PSImmich',
},
{
title: 'Immich Distribution',
description: 'Snap package for easy install and zero-care auto updates of Immich. Self-hosted photo management.',
url: 'https://immich-distribution.nsg.cc',
},
];
function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {

View File

@@ -49,7 +49,7 @@ export function Timeline({ items }: Props): JSX.Element {
<div className="flex flex-col flex-grow justify-between gap-2">
<div className="flex gap-2 items-center">
{cardIcon === 'immich' ? (
<img src="img/immich-logo.svg" height="30" />
<img src="img/immich-logo.svg" height="30" className="rounded-none" />
) : (
<Icon path={cardIcon} size={1} color={item.iconColor} />
)}

View File

@@ -8,7 +8,6 @@
@tailwind utilities;
@import url('https://fonts.googleapis.com/css2?family=Overpass:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Snowburst+One&display=swap');
html,
button {
@@ -48,7 +47,3 @@ img {
div[class^='announcementBar_'] {
min-height: 2rem;
}
.navbar__brand .navbar__title {
@apply font-immich-title text-2xl font-normal text-immich-primary dark:text-immich-dark-primary;
}

View File

@@ -0,0 +1,121 @@
import {
mdiCalendarToday,
mdiCrosshairsOff,
mdiLeadPencil,
mdiLockOff,
mdiLockOutline,
mdiSpeedometerSlow,
mdiWeb,
mdiWrap,
} from '@mdi/js';
import Layout from '@theme/Layout';
import React from 'react';
import { Item as TimelineItem, Timeline } from '../components/timeline';
const withLanguage = (date: Date) => (language: string) => date.toLocaleDateString(language);
type Item = Omit<TimelineItem, 'done' | 'getDateLabel'> & { date: Date };
const items: Item[] = [
{
icon: mdiWrap,
iconColor: 'gray',
title: 'Carriage returns in bash scripts are cursed',
description: 'Git can be configured to automatically convert LF to CRLF on checkout and CRLF breaks bash scripts.',
link: {
url: 'https://github.com/immich-app/immich/pull/11613',
text: '#11613',
},
date: new Date(2024, 7, 7),
},
{
icon: mdiLockOff,
iconColor: 'red',
title: 'Fetch inside Cloudflare Workers is cursed',
description:
'Fetch requests in Cloudflare Workers use http by default, even if you explicitly specify https, which can often cause redirect loops.',
link: {
url: 'https://community.cloudflare.com/t/does-cloudflare-worker-allow-secure-https-connection-to-fetch-even-on-flexible-ssl/68051/5',
text: 'Cloudflare',
},
date: new Date(2024, 7, 7),
},
{
icon: mdiCrosshairsOff,
iconColor: 'gray',
title: 'GPS sharing on mobile is cursed',
description:
'Some phones will silently strip GPS data from images when apps without location permission try to access them.',
link: {
url: 'https://github.com/immich-app/immich/discussions/11268',
text: '#11268',
},
date: new Date(2024, 6, 21),
},
{
icon: mdiLeadPencil,
iconColor: 'gold',
title: 'PostgreSQL NOTIFY is cursed',
description:
'PostgreSQL does everything in a transaction, including NOTIFY. This means using the socket.io postgres-adapter writes to WAL every 5 seconds.',
link: { url: 'https://github.com/immich-app/immich/pull/10801', text: '#10801' },
date: new Date(2024, 6, 3),
},
{
icon: mdiWeb,
iconColor: 'lightskyblue',
title: 'npm scripts are cursed',
description:
'npm scripts make a http call to the npm registry each time they run, which means they are a terrible way to execute a health check.',
link: { url: 'https://github.com/immich-app/immich/issues/10796', text: '#10796' },
date: new Date(2024, 6, 3),
},
{
icon: mdiSpeedometerSlow,
iconColor: 'brown',
title: '50 extra packages are cursed',
description:
'There is a user in the JavaScript community who goes around adding "backwards compatibility" to projects. They do this by adding 50 extra package dependencies to your project, which are maintained by them.',
link: { url: 'https://github.com/immich-app/immich/pull/10690', text: '#10690' },
date: new Date(2024, 5, 28),
},
{
icon: mdiLockOutline,
iconColor: 'gold',
title: 'Long passwords are cursed',
description:
'The bcrypt implementation only uses the first 72 bytes of a string. Any characters after that are ignored.',
// link: GHSA-4p64-9f7h-3432
date: new Date(2024, 5, 25),
},
{
icon: mdiCalendarToday,
iconColor: 'greenyellow',
title: 'JavaScript Date objects are cursed',
description: 'JavaScript date objects are 1 indexed for years and days, but 0 indexed for months.',
link: { url: 'https://github.com/immich-app/immich/pull/6787', text: '#6787' },
date: new Date(2024, 0, 31),
},
];
export default function CursedKnowledgePage(): JSX.Element {
return (
<Layout title="Cursed Knowledge" description="Things we wish we didn't know">
<section className="my-8">
<h1 className="md:text-6xl text-center mb-10 text-immich-primary dark:text-immich-dark-primary px-2">
Cursed Knowledge
</h1>
<p className="text-center text-xl px-2">
Cursed knowledge we have learned as a result of building Immich that we wish we never knew.
</p>
<div className="flex justify-around mt-8 w-full max-w-full">
<Timeline
items={items
.sort((a, b) => b.date.getTime() - a.date.getTime())
.map((item) => ({ ...item, getDateLabel: withLanguage(item.date) }))}
/>
</div>
</section>
</Layout>
);
}

View File

@@ -10,7 +10,7 @@ function HomepageHeader() {
<section className="text-center m-6 p-12 border border-red-400 rounded-[50px] bg-slate-200 dark:bg-immich-dark-gray">
<img
src={isDarkTheme ? 'img/immich-logo-stacked-dark.svg' : 'img/immich-logo-stacked-light.svg'}
className="md:h-60 h-44 mb-2 antialiased"
className="md:h-60 h-44 mb-2 antialiased rounded-none"
alt="Immich logo"
/>
<div className="sm:text-2xl text-lg md:text-4xl mb-12 sm:leading-tight">
@@ -36,12 +36,12 @@ function HomepageHeader() {
<Link
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-dark-primary dark:bg-immich-primary rounded-full hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase"
to="https://discord.gg/D8JsnBEuKb"
to="https://discord.immich.app"
>
Discord
</Link>
</div>
<img src="/img/immich-screenshots.png" alt="screenshots" width={'70%'} />
<img src="/img/immich-screenshots.webp" alt="screenshots" width={'70%'} />
<div className="flex flex-col sm:flex-row place-items-center place-content-center mt-4 gap-1">
<div className="h-24">
<a href="https://play.google.com/store/apps/details?id=app.alextran.immich">

View File

@@ -0,0 +1,114 @@
import React from 'react';
import Link from '@docusaurus/Link';
import Layout from '@theme/Layout';
import { useColorMode } from '@docusaurus/theme-common';
function HomepageHeader() {
const { isDarkTheme } = useColorMode();
return (
<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>
<h1>Privacy Policy</h1>
<p>Last updated: July 31st 2024</p>
<p>
Welcome to Immich. We are committed to respecting your privacy. This Privacy Policy sets out how we collect,
use, and share information when you use our Immich app.
</p>
</section>
{/* 1. Scope of This Policy */}
<section>
<h2>1. Scope of This Policy</h2>
<p>
This Privacy Policy applies to the Immich app ("we", "our", or "us") and covers our collection, use, and
disclosure of your information. This Policy does not cover any third-party websites, services, or
applications that can be accessed through our app, or third-party services you may access through Immich.
</p>
</section>
{/* 2. Information We Collect */}
<section>
<h2>2. Information We Collect</h2>
<div>
<p>
<strong>Locally Stored Data</strong>: Immich stores all your photos, albums, settings, and locally on your
device. We do not have access to this data, nor do we transmit or store it on any of our servers.
</p>
</div>
<div>
<p>
<strong>Purchase Information:</strong> When you make a purchase within the{' '}
<a href="https://buy.immich.app">https://buy.immich.app</a>, we collect the following information for tax
calculation purposes:
</p>
<ul>
<li>Country of origin</li>
<li>Postal code (if the user is from Canada or the United States)</li>
</ul>
</div>
</section>
{/* 3. Use of Your Information */}
<section>
<h2>3. Use of Your Information</h2>
<p>
<strong>Tax Calculation:</strong> The country of origin and postal code (for users from Canada or the United
States) are collected solely for determining the applicable tax rates on your purchase.
</p>
</section>
{/* 4. Sharing of Your Information */}
<section>
<h2>4. Sharing of Your Information</h2>
<ul>
<li>
<strong>Tax Authorities:</strong> The purchase information may be shared with tax authorities as required
by law.
</li>
<li>
<strong>Payment Providers:</strong> The purchase information may be shared with payment providers where
required.
</li>
</ul>
</section>
{/* 5. Changes to This Policy */}
<section>
<h2>5. Changes to This Policy</h2>
<p>
We may update our Privacy Policy from time to time. If we make any changes, we will notify you by revising
the "Last updated" date at the top of this policy. It's encouraged that users frequently check this page for
any changes to stay informed about how we are helping to protect the personal information we collect.
</p>
</section>
{/* 6. Contact Us */}
<section>
<h2>6. Contact Us</h2>
<p>
If you have any questions about this Privacy Policy, please contact us at{' '}
<a href="mailto:immich@futo.org">immich@futo.org</a>
</p>
</section>
</section>
</header>
);
}
export default function Home(): JSX.Element {
return (
<Layout
title="Home"
description="immich Self-hosted photo and video backup solution directly from your mobile phone "
noFooter={true}
>
<HomepageHeader />
<div className="flex flex-col place-items-center place-content-center">
<p>This project is available under GNU AGPL v3 license.</p>
<p className="text-xs">Privacy should not be a luxury</p>
</div>
</Layout>
);
}

View File

@@ -14,6 +14,7 @@ import {
mdiCheckboxMarked,
mdiCloudUploadOutline,
mdiCollage,
mdiContentDuplicate,
mdiDevices,
mdiEmailOutline,
mdiExpansionCard,
@@ -28,12 +29,14 @@ import {
mdiForum,
mdiHandshakeOutline,
mdiHeart,
mdiHistory,
mdiImage,
mdiImageAlbum,
mdiImageEdit,
mdiImageMultipleOutline,
mdiImageSearch,
mdiKeyboardSettingsOutline,
mdiLockOutline,
mdiMagnify,
mdiMagnifyScan,
mdiMap,
@@ -63,14 +66,17 @@ import {
mdiVectorCombine,
mdiVideo,
mdiWeb,
mdiContentDuplicate,
mdiLicense,
} from '@mdi/js';
import Layout from '@theme/Layout';
import React from 'react';
import { Item, Timeline } from '../components/timeline';
const releases = {
'v1.106.0': new Date(2024, 5, 11),
// TODO
'v1.110.0': new Date(2024, 5, 11),
'v1.109.0': new Date(2024, 6, 18),
'v1.106.1': new Date(2024, 5, 11),
'v1.104.0': new Date(2024, 4, 13),
'v1.103.0': new Date(2024, 3, 29),
'v1.102.0': new Date(2024, 3, 15),
@@ -159,6 +165,14 @@ const withRelease = ({
};
const roadmap: Item[] = [
{
done: false,
icon: mdiLockOutline,
iconColor: 'sandybrown',
title: 'Private/locked photos',
description: 'Private assets with extra protections',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiRocketLaunch,
@@ -199,14 +213,6 @@ const roadmap: Item[] = [
description: 'Granular access controls for users and api keys',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiWeb,
iconColor: 'royalblue',
title: 'Web translations',
description: 'Translate the web application to multiple languages',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiCameraBurst,
@@ -218,18 +224,45 @@ const roadmap: Item[] = [
];
const milestones: Item[] = [
{
icon: mdiStar,
iconColor: 'gold',
title: '40,000 Stars',
description: 'Reached 40K Stars on GitHub!',
getDateLabel: withLanguage(new Date(2024, 6, 21)),
},
withRelease({
icon: mdiLicense,
iconColor: 'gold',
title: 'Supporter Badge',
description: 'The option to buy Immich to support its development!',
release: 'v1.109.0',
}),
withRelease({
icon: mdiHistory,
title: 'Versioned documentation',
description: 'View documentation as it was at the time of past releases',
release: 'v1.106.1',
}),
withRelease({
icon: mdiWeb,
iconColor: 'royalblue',
title: 'Web translations',
description: 'Translate the web application to multiple languages',
release: 'v1.106.1',
}),
withRelease({
icon: mdiContentDuplicate,
title: 'Similar image detection',
description: 'Detect duplicate assets that arent exactly identical',
release: 'v1.106.0',
description: "Detect duplicate assets that aren't exactly identical",
release: 'v1.106.1',
}),
withRelease({
icon: mdiVectorCombine,
title: 'Container consolidation',
description:
'The microservices container can be run as a worker within the server image, allowing us to remove it from the default stack.',
release: 'v1.106.0',
release: 'v1.106.1',
}),
withRelease({
icon: mdiPencil,

View File

@@ -1,4 +1,52 @@
[
{
"label": "v1.112.0",
"url": "https://v1.112.0.archive.immich.app"
},
{
"label": "v1.111.0",
"url": "https://v1.111.0.archive.immich.app"
},
{
"label": "v1.110.0",
"url": "https://v1.110.0.archive.immich.app"
},
{
"label": "v1.109.2",
"url": "https://v1.109.2.archive.immich.app"
},
{
"label": "v1.109.1",
"url": "https://v1.109.1.archive.immich.app"
},
{
"label": "v1.109.0",
"url": "https://v1.109.0.archive.immich.app"
},
{
"label": "v1.108.0",
"url": "https://v1.108.0.archive.immich.app"
},
{
"label": "v1.107.2",
"url": "https://v1.107.2.archive.immich.app"
},
{
"label": "v1.107.1",
"url": "https://v1.107.1.archive.immich.app"
},
{
"label": "v1.107.0",
"url": "https://v1.107.0.archive.immich.app"
},
{
"label": "v1.106.4",
"url": "https://v1.106.4.archive.immich.app"
},
{
"label": "v1.106.3",
"url": "https://v1.106.3.archive.immich.app"
},
{
"label": "v1.106.2",
"url": "https://v1.106.2.archive.immich.app"

BIN
docs/static/img/immich-screenshots.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

View File

@@ -21,9 +21,6 @@ module.exports = {
'immich-dark-fg': '#e5e7eb',
'immich-dark-gray': '#212121',
},
fontFamily: {
'immich-title': ['Snowburst One', 'cursive'],
},
},
},
plugins: [],

View File

@@ -1,32 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'plugin:unicorn/recommended'],
root: true,
env: {
node: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/import-style': 'off',
curly: 2,
'prettier/prettier': 0,
'unicorn/prevent-abbreviations': 'off',
'unicorn/filename-case': 'off',
'unicorn/no-null': 'off',
'unicorn/prefer-top-level-await': 'off',
'unicorn/prefer-event-target': 'off',
'unicorn/no-thenable': 'off',
},
};

View File

@@ -1 +1 @@
20.14
20.16.0

View File

@@ -10,6 +10,11 @@ services:
build:
context: ../
dockerfile: server/Dockerfile
args:
- BUILD_ID=1234567890
- BUILD_IMAGE=e2e
- BUILD_SOURCE_REF=e2e
- BUILD_SOURCE_COMMIT=e2eeeeeeeeeeeeeeeeee
environment:
- DB_HOSTNAME=database
- DB_USERNAME=postgres
@@ -17,9 +22,12 @@ services:
- DB_DATABASE_NAME=immich
- IMMICH_MACHINE_LEARNING_ENABLED=false
- IMMICH_METRICS=true
- IMMICH_ENV=testing
volumes:
- upload:/usr/src/app/upload
- ./test-assets:/test-assets
extra_hosts:
- 'auth-server:host-gateway'
depends_on:
- redis
- database
@@ -27,7 +35,7 @@ services:
- 2283:3001
redis:
image: redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900
image: redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e
database:
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0

64
e2e/eslint.config.mjs Normal file
View File

@@ -0,0 +1,64 @@
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import globals from 'globals';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
{
ignores: ['eslint.config.mjs'],
},
...compat.extends(
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'plugin:unicorn/recommended',
),
{
plugins: {
'@typescript-eslint': typescriptEslint,
},
languageOptions: {
globals: {
...globals.node,
},
parser: tsParser,
ecmaVersion: 5,
sourceType: 'module',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
},
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/import-style': 'off',
curly: 2,
'prettier/prettier': 0,
'unicorn/prevent-abbreviations': 'off',
'unicorn/filename-case': 'off',
'unicorn/no-null': 'off',
'unicorn/prefer-top-level-await': 'off',
'unicorn/prefer-event-target': 'off',
'unicorn/no-thenable': 'off',
},
},
];

2832
e2e/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "1.106.2",
"version": "1.112.0",
"description": "",
"main": "index.js",
"type": "module",
@@ -19,34 +19,40 @@
"author": "",
"license": "GNU Affero General Public License version 3",
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/cli": "file:../cli",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@playwright/test": "^1.44.1",
"@types/luxon": "^3.4.2",
"@types/node": "^20.11.17",
"@types/node": "^20.14.14",
"@types/oidc-provider": "^8.5.1",
"@types/pg": "^8.11.0",
"@types/pngjs": "^6.0.4",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"@vitest/coverage-v8": "^1.3.0",
"eslint": "^8.57.0",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"@vitest/coverage-v8": "^2.0.5",
"eslint": "^9.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^53.0.0",
"exiftool-vendored": "^26.0.0",
"eslint-plugin-unicorn": "^55.0.0",
"exiftool-vendored": "^28.0.0",
"globals": "^15.9.0",
"jose": "^5.6.3",
"luxon": "^3.4.4",
"oidc-provider": "^8.5.1",
"pg": "^8.11.3",
"pngjs": "^7.0.0",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-organize-imports": "^4.0.0",
"socket.io-client": "^4.7.4",
"supertest": "^7.0.0",
"typescript": "^5.3.3",
"utimes": "^5.2.1",
"vitest": "^1.3.0"
"vitest": "^2.0.5"
},
"volta": {
"node": "20.14.0"
"node": "20.16.0"
}
}

View File

@@ -88,7 +88,7 @@ describe('/albums', () => {
});
await addAssetsToAlbum(
{ id: user2Albums[0].id, bulkIdsDto: { ids: [user1Asset1.id] } },
{ id: user2Albums[0].id, bulkIdsDto: { ids: [user1Asset1.id, user1Asset2.id] } },
{ headers: asBearerAuth(user1.accessToken) },
);
@@ -261,7 +261,7 @@ describe('/albums', () => {
.get(`/albums?assetId=${user1Asset2.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(1);
expect(body).toHaveLength(2);
});
it('should return the album collection filtered by assetId and ignores shared=true', async () => {
@@ -509,7 +509,17 @@ describe('/albums', () => {
expect(body).toEqual(errorDto.unauthorized);
});
it('should not be able to remove foreign asset from own album', async () => {
it('should require authorization', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user1Albums[1].id}/assets`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ ids: [user1Asset1.id] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.noPermission);
});
it('should be able to remove foreign asset from owned album', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user2Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user2.accessToken}`)
@@ -519,8 +529,7 @@ describe('/albums', () => {
expect(body).toEqual([
expect.objectContaining({
id: user1Asset1.id,
success: false,
error: 'no_permission',
success: true,
}),
]);
});
@@ -555,10 +564,10 @@ describe('/albums', () => {
const { status, body } = await request(app)
.delete(`/albums/${user2Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ ids: [user1Asset1.id] });
.send({ ids: [user1Asset2.id] });
expect(status).toBe(200);
expect(body).toEqual([expect.objectContaining({ id: user1Asset1.id, success: true })]);
expect(body).toEqual([expect.objectContaining({ id: user1Asset2.id, success: true })]);
});
it('should not be able to remove assets from album as a viewer', async () => {

View File

@@ -43,6 +43,7 @@ const makeUploadDto = (options?: { omit: string }): Record<string, any> => {
const TEN_TIMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const locationAssetFilepath = `${testAssetDir}/metadata/gps-position/thompson-springs.jpg`;
const ratingAssetFilepath = `${testAssetDir}/metadata/rating/mongolels.jpg`;
const readTags = async (bytes: Buffer, filename: string) => {
const filepath = join(tempDir, filename);
@@ -72,6 +73,7 @@ describe('/asset', () => {
let user2Assets: AssetMediaResponseDto[];
let stackAssets: AssetMediaResponseDto[];
let locationAsset: AssetMediaResponseDto;
let ratingAsset: AssetMediaResponseDto;
const setupTests = async () => {
await utils.resetDatabase();
@@ -99,6 +101,16 @@ describe('/asset', () => {
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: locationAsset.id });
// asset rating
ratingAsset = await utils.createAsset(admin.accessToken, {
assetData: {
filename: 'mongolels.jpg',
bytes: await readFile(ratingAssetFilepath),
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: ratingAsset.id });
user1Assets = await Promise.all([
utils.createAsset(user1.accessToken),
utils.createAsset(user1.accessToken),
@@ -214,6 +226,22 @@ describe('/asset', () => {
expect(body).toMatchObject({ id: user1Assets[0].id });
});
it('should get the asset rating', async () => {
await utils.waitForWebsocketEvent({
event: 'assetUpload',
id: ratingAsset.id,
});
const { status, body } = await request(app)
.get(`/assets/${ratingAsset.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: ratingAsset.id,
exifInfo: expect.objectContaining({ rating: 3 }),
});
});
it('should work with a shared link', async () => {
const sharedLink = await utils.createSharedLink(user1.accessToken, {
type: SharedLinkType.Individual,
@@ -472,6 +500,44 @@ describe('/asset', () => {
expect(status).toEqual(200);
});
it('should update date time original when sidecar file contains DateTimeOriginal', async () => {
const sidecarData = `<?xpacket begin='?' id='W5M0MpCehiHzreSzNTczkc9d'?>
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 12.40'>
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<rdf:Description rdf:about=''
xmlns:exif='http://ns.adobe.com/exif/1.0/'>
<exif:ExifVersion>0220</exif:ExifVersion> <exif:DateTimeOriginal>2024-07-11T10:32:52Z</exif:DateTimeOriginal>
<exif:GPSVersionID>2.3.0.0</exif:GPSVersionID>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end='w'?>`;
const { id } = await utils.createAsset(user1.accessToken, {
sidecarData: {
bytes: Buffer.from(sidecarData),
filename: 'example.xmp',
},
});
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
const assetInfo = await utils.getAssetInfo(user1.accessToken, id);
expect(assetInfo.exifInfo?.dateTimeOriginal).toBe('2024-07-11T10:32:52.000Z');
const { status, body } = await request(app)
.put(`/assets/${id}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ dateTimeOriginal: '2023-11-19T18:11:00.000-07:00' });
expect(body).toMatchObject({
id,
exifInfo: expect.objectContaining({
dateTimeOriginal: '2023-11-20T01:11:00.000Z',
}),
});
expect(status).toEqual(200);
});
it('should reject invalid gps coordinates', async () => {
for (const test of [
{ latitude: 12 },
@@ -507,6 +573,22 @@ describe('/asset', () => {
expect(status).toEqual(200);
});
it.skip('should geocode country from gps data in the middle of nowhere', async () => {
const { status } = await request(app)
.put(`/assets/${user1Assets[0].id}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ latitude: 42, longitude: 69 });
expect(status).toEqual(200);
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
const asset = await getAssetInfo({ id: user1Assets[0].id }, { headers: asBearerAuth(user1.accessToken) });
expect(asset).toMatchObject({
id: user1Assets[0].id,
exifInfo: expect.objectContaining({ city: null, country: 'Kazakhstan' }),
});
});
it('should set the description', async () => {
const { status, body } = await request(app)
.put(`/assets/${user1Assets[0].id}`)
@@ -521,6 +603,31 @@ describe('/asset', () => {
expect(status).toEqual(200);
});
it('should set the rating', async () => {
const { status, body } = await request(app)
.put(`/assets/${user1Assets[0].id}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ rating: 2 });
expect(body).toMatchObject({
id: user1Assets[0].id,
exifInfo: expect.objectContaining({
rating: 2,
}),
});
expect(status).toEqual(200);
});
it('should reject invalid rating', async () => {
for (const test of [{ rating: 7 }, { rating: 3.5 }, { rating: null }]) {
const { status, body } = await request(app)
.put(`/assets/${user1Assets[0].id}`)
.send(test)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
}
});
it('should return tagged people', async () => {
const { status, body } = await request(app)
.put(`/assets/${user1Assets[0].id}`)
@@ -588,6 +695,58 @@ describe('/asset', () => {
const after = await utils.getAssetInfo(admin.accessToken, assetId);
expect(after.isTrashed).toBe(true);
});
it('should clean up live photos', async () => {
const { id: motionId } = await utils.createAsset(admin.accessToken, {
assetData: { filename: 'test.mp4', bytes: makeRandomImage() },
});
const { id: photoId } = await utils.createAsset(admin.accessToken, { livePhotoVideoId: motionId });
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: photoId });
await utils.waitForWebsocketEvent({ event: 'assetHidden', id: motionId });
const asset = await utils.getAssetInfo(admin.accessToken, photoId);
expect(asset.livePhotoVideoId).toBe(motionId);
const { status } = await request(app)
.delete('/assets')
.send({ ids: [photoId], force: true })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(204);
await utils.waitForWebsocketEvent({ event: 'assetDelete', id: photoId });
await utils.waitForWebsocketEvent({ event: 'assetDelete', id: motionId });
});
it('should not delete a shared motion asset', async () => {
const { id: motionId } = await utils.createAsset(admin.accessToken, {
assetData: { filename: 'test.mp4', bytes: makeRandomImage() },
});
const { id: asset1 } = await utils.createAsset(admin.accessToken, { livePhotoVideoId: motionId });
const { id: asset2 } = await utils.createAsset(admin.accessToken, { livePhotoVideoId: motionId });
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset1 });
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset2 });
await utils.waitForWebsocketEvent({ event: 'assetHidden', id: motionId });
const asset = await utils.getAssetInfo(admin.accessToken, asset1);
expect(asset.livePhotoVideoId).toBe(motionId);
const { status } = await request(app)
.delete('/assets')
.send({ ids: [asset1], force: true })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(204);
await utils.waitForWebsocketEvent({ event: 'assetDelete', id: asset1 });
await utils.waitForQueueFinish(admin.accessToken, 'backgroundTask');
await expect(utils.getAssetInfo(admin.accessToken, motionId)).resolves.toMatchObject({ id: motionId });
await expect(utils.getAssetInfo(admin.accessToken, asset2)).resolves.toMatchObject({
id: asset2,
livePhotoVideoId: motionId,
});
});
});
describe('GET /assets/:id/thumbnail', () => {
@@ -1031,7 +1190,7 @@ describe('/asset', () => {
type: AssetTypeEnum.Image,
originalFileName: '14bit-uncompressed-(3_2).arw',
resized: true,
fileCreatedAt: '2016-01-08T15:08:01.000Z',
fileCreatedAt: '2016-01-08T14:08:01.000Z',
exifInfo: {
make: 'SONY',
model: 'ILCE-7M2',
@@ -1043,7 +1202,7 @@ describe('/asset', () => {
iso: 100,
lensModel: 'E 25mm F2',
fileSizeInByte: 49_512_448,
dateTimeOriginal: '2016-01-08T15:08:01.000Z',
dateTimeOriginal: '2016-01-08T14:08:01.000Z',
latitude: null,
longitude: null,
orientation: '1',
@@ -1118,17 +1277,25 @@ describe('/asset', () => {
// into the test here.
it.each([
{
filepath: 'formats/motionphoto/Samsung One UI 5.jpg',
filepath: 'formats/motionphoto/samsung-one-ui-5.jpg',
checksum: 'fr14niqCq6N20HB8rJYEvpsUVtI=',
},
{
filepath: 'formats/motionphoto/Samsung One UI 6.jpg',
filepath: 'formats/motionphoto/samsung-one-ui-6.jpg',
checksum: 'lT9Uviw/FFJYCjfIxAGPTjzAmmw=',
},
{
filepath: 'formats/motionphoto/Samsung One UI 6.heic',
filepath: 'formats/motionphoto/samsung-one-ui-6.heic',
checksum: '/ejgzywvgvzvVhUYVfvkLzFBAF0=',
},
{
filepath: 'formats/motionphoto/pixel-6-pro.jpg',
checksum: 'bFhLGbdK058PSk4FTfrSnoKWykc=',
},
{
filepath: 'formats/motionphoto/pixel-8a.jpg',
checksum: '7YdY+WF0h+CXHbiXpi0HiCMTTjs=',
},
])(`should extract motionphoto video from $filepath`, async ({ filepath, checksum }) => {
const response = await utils.createAsset(admin.accessToken, {
assetData: {
@@ -1148,4 +1315,29 @@ describe('/asset', () => {
expect(video.checksum).toStrictEqual(checksum);
});
});
describe('POST /assets/exist', () => {
it('ignores invalid deviceAssetIds', async () => {
const response = await utils.checkExistingAssets(user1.accessToken, {
deviceId: 'test-assets-exist',
deviceAssetIds: ['invalid', 'INVALID'],
});
expect(response.existingIds).toHaveLength(0);
});
it('returns the IDs of existing assets', async () => {
await utils.createAsset(user1.accessToken, {
deviceId: 'test-assets-exist',
deviceAssetId: 'test-asset-0',
});
const response = await utils.checkExistingAssets(user1.accessToken, {
deviceId: 'test-assets-exist',
deviceAssetIds: ['test-asset-0'],
});
expect(response.existingIds).toEqual(['test-asset-0']);
});
});
});

View File

@@ -100,6 +100,12 @@ describe('/auth/*', () => {
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
it('should reject an invalid email', async () => {
const { status, body } = await request(app).post('/auth/login').send({ email: [], password });
expect(status).toBe(400);
expect(body).toEqual(errorDto.invalidEmail);
});
}
it('should accept a correct password', async () => {

View File

@@ -159,4 +159,75 @@ describe('/map', () => {
expect(body).toEqual(expect.objectContaining({ id: 'immich-map-dark' }));
});
});
describe('GET /map/reverse-geocode', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/map/reverse-geocode');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should throw an error if a lat is not provided', async () => {
const { status, body } = await request(app)
.get('/map/reverse-geocode?lon=123')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['lat must be a number between -90 and 90']));
});
it('should throw an error if a lat is not a number', async () => {
const { status, body } = await request(app)
.get('/map/reverse-geocode?lat=abc&lon=123.456')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['lat must be a number between -90 and 90']));
});
it('should throw an error if a lat is out of range', async () => {
const { status, body } = await request(app)
.get('/map/reverse-geocode?lat=91&lon=123.456')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['lat must be a number between -90 and 90']));
});
it('should throw an error if a lon is not provided', async () => {
const { status, body } = await request(app)
.get('/map/reverse-geocode?lat=75')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['lon must be a number between -180 and 180']));
});
const reverseGeocodeTestCases = [
{
name: 'Vaucluse',
lat: -33.858_977_058_663_13,
lon: 151.278_490_730_270_48,
results: [{ city: 'Vaucluse', state: 'New South Wales', country: 'Australia' }],
},
{
name: 'Ravenhall',
lat: -37.765_732_399_174_75,
lon: 144.752_453_164_883_3,
results: [{ city: 'Ravenhall', state: 'Victoria', country: 'Australia' }],
},
{
name: 'Scarborough',
lat: -31.894_346_156_789_997,
lon: 115.757_617_103_904_64,
results: [{ city: 'Scarborough', state: 'Western Australia', country: 'Australia' }],
},
];
it.each(reverseGeocodeTestCases)(`should resolve to $name`, async ({ lat, lon, results }) => {
const { status, body } = await request(app)
.get(`/map/reverse-geocode?lat=${lat}&lon=${lon}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(Array.isArray(body)).toBe(true);
expect(body.length).toBe(results.length);
expect(body).toEqual(results);
});
});
});

View File

@@ -1,12 +1,85 @@
import {
LoginResponseDto,
SystemConfigOAuthDto,
getConfigDefaults,
getMyUser,
startOAuth,
updateConfig,
} from '@immich/sdk';
import { errorDto } from 'src/responses';
import { app, utils } from 'src/utils';
import { OAuthClient, OAuthUser } from 'src/setup/auth-server';
import { app, asBearerAuth, baseUrl, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, describe, expect, it } from 'vitest';
const authServer = {
internal: 'http://auth-server:3000',
external: 'http://127.0.0.1:3000',
};
const redirect = async (url: string, cookies?: string[]) => {
const { headers } = await request(url)
.get('/')
.set('Cookie', cookies || []);
return { cookies: (headers['set-cookie'] as unknown as string[]) || [], location: headers.location };
};
const loginWithOAuth = async (sub: OAuthUser | string) => {
const { url } = await startOAuth({ oAuthConfigDto: { redirectUri: `${baseUrl}/auth/login` } });
// login
const response1 = await redirect(url.replace(authServer.internal, authServer.external));
const response2 = await request(authServer.external + response1.location)
.post('/')
.set('Cookie', response1.cookies)
.type('form')
.send({ prompt: 'login', login: sub, password: 'password' });
// approve
const response3 = await redirect(response2.header.location, response1.cookies);
const response4 = await request(authServer.external + response3.location)
.post('/')
.type('form')
.set('Cookie', response3.cookies)
.send({ prompt: 'consent' });
const response5 = await redirect(response4.header.location, response3.cookies.slice(1));
const redirectUrl = response5.location;
expect(redirectUrl).toBeDefined();
const params = new URL(redirectUrl).searchParams;
expect(params.get('code')).toBeDefined();
expect(params.get('state')).toBeDefined();
return redirectUrl;
};
const setupOAuth = async (token: string, dto: Partial<SystemConfigOAuthDto>) => {
const options = { headers: asBearerAuth(token) };
const defaults = await getConfigDefaults(options);
const merged = {
...defaults.oauth,
buttonText: 'Login with Immich',
issuerUrl: `${authServer.internal}/.well-known/openid-configuration`,
...dto,
};
await updateConfig({ systemConfigDto: { ...defaults, oauth: merged } }, options);
};
describe(`/oauth`, () => {
let admin: LoginResponseDto;
beforeAll(async () => {
await utils.resetDatabase();
await utils.adminSetup();
admin = await utils.adminSetup();
await setupOAuth(admin.accessToken, {
enabled: true,
clientId: OAuthClient.DEFAULT,
clientSecret: OAuthClient.DEFAULT,
buttonText: 'Login with Immich',
storageLabelClaim: 'immich_username',
});
});
describe('POST /oauth/authorize', () => {
@@ -15,5 +88,171 @@ describe(`/oauth`, () => {
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['redirectUri must be a string', 'redirectUri should not be empty']));
});
it('should return a redirect uri', async () => {
const { status, body } = await request(app)
.post('/oauth/authorize')
.send({ redirectUri: 'http://127.0.0.1:2283/auth/login' });
expect(status).toBe(201);
expect(body).toEqual({ url: expect.stringContaining(`${authServer.internal}/auth?`) });
const params = new URL(body.url).searchParams;
expect(params.get('client_id')).toBe('client-default');
expect(params.get('response_type')).toBe('code');
expect(params.get('redirect_uri')).toBe('http://127.0.0.1:2283/auth/login');
expect(params.get('state')).toBeDefined();
});
});
describe('POST /oauth/callback', () => {
it(`should throw an error if a url is not provided`, async () => {
const { status, body } = await request(app).post('/oauth/callback').send({});
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['url must be a string', 'url should not be empty']));
});
it(`should throw an error if the url is empty`, async () => {
const { status, body } = await request(app).post('/oauth/callback').send({ url: '' });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['url should not be empty']));
});
it('should auto register the user by default', async () => {
const url = await loginWithOAuth('oauth-auto-register');
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(201);
expect(body).toMatchObject({
accessToken: expect.any(String),
isAdmin: false,
name: 'OAuth User',
userEmail: 'oauth-auto-register@immich.app',
userId: expect.any(String),
});
});
it('should handle a user without an email', async () => {
const url = await loginWithOAuth(OAuthUser.NO_EMAIL);
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest('OAuth profile does not have an email address'));
});
it('should set the quota from a claim', async () => {
const url = await loginWithOAuth(OAuthUser.WITH_QUOTA);
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(201);
expect(body).toMatchObject({
accessToken: expect.any(String),
userId: expect.any(String),
userEmail: 'oauth-with-quota@immich.app',
});
const user = await getMyUser({ headers: asBearerAuth(body.accessToken) });
expect(user.quotaSizeInBytes).toBe(25 * 2 ** 30); // 25 GiB;
});
it('should set the storage label from a claim', async () => {
const url = await loginWithOAuth(OAuthUser.WITH_USERNAME);
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(201);
expect(body).toMatchObject({
accessToken: expect.any(String),
userId: expect.any(String),
userEmail: 'oauth-with-username@immich.app',
});
const user = await getMyUser({ headers: asBearerAuth(body.accessToken) });
expect(user.storageLabel).toBe('user-username');
});
it('should work with RS256 signed tokens', async () => {
await setupOAuth(admin.accessToken, {
enabled: true,
clientId: OAuthClient.RS256_TOKENS,
clientSecret: OAuthClient.RS256_TOKENS,
autoRegister: true,
buttonText: 'Login with Immich',
signingAlgorithm: 'RS256',
});
const url = await loginWithOAuth('oauth-RS256-token');
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(201);
expect(body).toMatchObject({
accessToken: expect.any(String),
isAdmin: false,
name: 'OAuth User',
userEmail: 'oauth-RS256-token@immich.app',
userId: expect.any(String),
});
});
it('should work with RS256 signed user profiles', async () => {
await setupOAuth(admin.accessToken, {
enabled: true,
clientId: OAuthClient.RS256_PROFILE,
clientSecret: OAuthClient.RS256_PROFILE,
buttonText: 'Login with Immich',
profileSigningAlgorithm: 'RS256',
});
const url = await loginWithOAuth('oauth-signed-profile');
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(201);
expect(body).toMatchObject({
userId: expect.any(String),
userEmail: 'oauth-signed-profile@immich.app',
});
});
it('should throw an error for an invalid token algorithm', async () => {
await setupOAuth(admin.accessToken, {
enabled: true,
clientId: OAuthClient.DEFAULT,
clientSecret: OAuthClient.DEFAULT,
buttonText: 'Login with Immich',
signingAlgorithm: 'something-that-does-not-work',
});
const url = await loginWithOAuth('oauth-signed-bad');
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(500);
expect(body).toMatchObject({
error: 'Internal Server Error',
message: 'Failed to finish oauth',
statusCode: 500,
});
});
describe('autoRegister: false', () => {
beforeAll(async () => {
await setupOAuth(admin.accessToken, {
enabled: true,
clientId: OAuthClient.DEFAULT,
clientSecret: OAuthClient.DEFAULT,
autoRegister: false,
buttonText: 'Login with Immich',
});
});
it('should not auto register the user', async () => {
const url = await loginWithOAuth('oauth-no-auto-register');
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest('User does not exist and auto registering is disabled.'));
});
it('should link to an existing user by email', async () => {
const { userId } = await utils.userSetup(admin.accessToken, {
name: 'OAuth User 3',
email: 'oauth-user3@immich.app',
password: 'password',
});
const url = await loginWithOAuth('oauth-user3');
const { status, body } = await request(app).post('/oauth/callback').send({ url });
expect(status).toBe(201);
expect(body).toMatchObject({
userId,
userEmail: 'oauth-user3@immich.app',
});
});
});
});
});

View File

@@ -6,10 +6,19 @@ import request from 'supertest';
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
const invalidBirthday = [
{ birthDate: 'false', response: 'birthDate must be a date string' },
{ birthDate: '123567', response: 'birthDate must be a date string' },
{ birthDate: 123_567, response: 'birthDate must be a date string' },
{ birthDate: new Date(9999, 0, 0).toISOString(), response: ['Birth date cannot be in the future'] },
{
birthDate: 'false',
response: ['birthDate must be a string in the format yyyy-MM-dd', 'Birth date cannot be in the future'],
},
{
birthDate: '123567',
response: ['birthDate must be a string in the format yyyy-MM-dd', 'Birth date cannot be in the future'],
},
{
birthDate: 123_567,
response: ['birthDate must be a string in the format yyyy-MM-dd', 'Birth date cannot be in the future'],
},
{ birthDate: '9999-01-01', response: ['Birth date cannot be in the future'] },
];
describe('/people', () => {
@@ -65,6 +74,7 @@ describe('/people', () => {
expect(status).toBe(200);
expect(body).toEqual({
hasNextPage: false,
total: 3,
hidden: 1,
people: [
@@ -80,6 +90,7 @@ describe('/people', () => {
expect(status).toBe(200);
expect(body).toEqual({
hasNextPage: false,
total: 3,
hidden: 1,
people: [
@@ -88,6 +99,21 @@ describe('/people', () => {
],
});
});
it('should support pagination', async () => {
const { status, body } = await request(app)
.get('/people')
.set('Authorization', `Bearer ${admin.accessToken}`)
.query({ withHidden: true, page: 2, size: 1 });
expect(status).toBe(200);
expect(body).toEqual({
hasNextPage: true,
total: 3,
hidden: 1,
people: [expect.objectContaining({ name: 'visible_person' })],
});
});
});
describe('GET /people/:id', () => {
@@ -168,13 +194,13 @@ describe('/people', () => {
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
name: 'New Person',
birthDate: '1990-01-01T05:00:00.000Z',
birthDate: '1990-01-01',
});
expect(status).toBe(201);
expect(body).toMatchObject({
id: expect.any(String),
name: 'New Person',
birthDate: '1990-01-01T05:00:00.000Z',
birthDate: '1990-01-01',
});
});
});
@@ -216,7 +242,7 @@ describe('/people', () => {
const { status, body } = await request(app)
.put(`/people/${visiblePerson.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ birthDate: '1990-01-01T05:00:00.000Z' });
.send({ birthDate: '1990-01-01' });
expect(status).toBe(200);
expect(body).toMatchObject({ birthDate: '1990-01-01' });
});
@@ -230,4 +256,21 @@ describe('/people', () => {
expect(body).toMatchObject({ birthDate: null });
});
});
describe('POST /people/:id/merge', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/people/${uuidDto.notFound}/merge`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should not supporting merging a person into themselves', async () => {
const { status, body } = await request(app)
.post(`/people/${visiblePerson.id}/merge`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ ids: [visiblePerson.id] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest('Cannot merge a person into themselves'));
});
});
});

View File

@@ -1,4 +1,4 @@
import { AssetMediaResponseDto, LoginResponseDto, deleteAssets, getMapMarkers, updateAsset } from '@immich/sdk';
import { AssetMediaResponseDto, LoginResponseDto, deleteAssets, updateAsset } from '@immich/sdk';
import { DateTime } from 'luxon';
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
@@ -32,9 +32,6 @@ describe('/search', () => {
let assetOneJpg5: AssetMediaResponseDto;
let assetSprings: AssetMediaResponseDto;
let assetLast: AssetMediaResponseDto;
let cities: string[];
let states: string[];
let countries: string[];
beforeAll(async () => {
await utils.resetDatabase();
@@ -49,9 +46,9 @@ describe('/search', () => {
{ filename: '/albums/nature/silver_fir.jpg' },
{ filename: '/formats/heic/IMG_2682.heic' },
{ filename: '/formats/jpg/el_torcal_rocks.jpg' },
{ filename: '/formats/motionphoto/Samsung One UI 6.jpg' },
{ filename: '/formats/motionphoto/Samsung One UI 6.heic' },
{ filename: '/formats/motionphoto/Samsung One UI 5.jpg' },
{ filename: '/formats/motionphoto/samsung-one-ui-6.jpg' },
{ filename: '/formats/motionphoto/samsung-one-ui-6.heic' },
{ filename: '/formats/motionphoto/samsung-one-ui-5.jpg' },
{ filename: '/metadata/gps-position/thompson-springs.jpg', dto: { isArchived: true } },
@@ -85,7 +82,7 @@ describe('/search', () => {
// note: the coordinates here are not the actual coordinates of the images and are random for most of them
const coordinates = [
{ latitude: 48.853_41, longitude: 2.3488 }, // paris
{ latitude: 63.0695, longitude: -151.0074 }, // denali
{ latitude: 35.6895, longitude: 139.691_71 }, // tokyo
{ latitude: 52.524_37, longitude: 13.410_53 }, // berlin
{ latitude: 1.314_663_1, longitude: 103.845_409_3 }, // singapore
{ latitude: 41.013_84, longitude: 28.949_66 }, // istanbul
@@ -101,16 +98,15 @@ describe('/search', () => {
{ latitude: 31.634_16, longitude: -7.999_94 }, // marrakesh
{ latitude: 38.523_735_4, longitude: -78.488_619_4 }, // tanners ridge
{ latitude: 59.938_63, longitude: 30.314_13 }, // st. petersburg
{ latitude: 35.6895, longitude: 139.691_71 }, // tokyo
];
const updates = assets.map((asset, i) =>
updateAsset({ id: asset.id, updateAssetDto: coordinates[i] }, { headers: asBearerAuth(admin.accessToken) }),
const updates = coordinates.map((dto, i) =>
updateAsset({ id: assets[i].id, updateAssetDto: dto }, { headers: asBearerAuth(admin.accessToken) }),
);
await Promise.all(updates);
for (const asset of assets) {
await utils.waitForWebsocketEvent({ event: 'assetUpdate', id: asset.id });
for (const [i] of coordinates.entries()) {
await utils.waitForWebsocketEvent({ event: 'assetUpdate', id: assets[i].id });
}
[
@@ -137,12 +133,6 @@ describe('/search', () => {
assetLast = assets.at(-1) as AssetMediaResponseDto;
await deleteAssets({ assetBulkDeleteDto: { ids: [assetSilver.id] } }, { headers: asBearerAuth(admin.accessToken) });
const mapMarkers = await getMapMarkers({}, { headers: asBearerAuth(admin.accessToken) });
const nonTrashed = mapMarkers.filter((mark) => mark.id !== assetSilver.id);
cities = [...new Set(nonTrashed.map((mark) => mark.city).filter((entry): entry is string => !!entry))].sort();
states = [...new Set(nonTrashed.map((mark) => mark.state).filter((entry): entry is string => !!entry))].sort();
countries = [...new Set(nonTrashed.map((mark) => mark.country).filter((entry): entry is string => !!entry))].sort();
}, 30_000);
afterAll(async () => {
@@ -315,29 +305,133 @@ describe('/search', () => {
{
should: 'should search by originalFilename with spaces',
deferred: () => ({
dto: { originalFileName: 'Samsung One', type: 'IMAGE' },
dto: { originalFileName: 'samsung-one', type: 'IMAGE' },
assets: [assetOneJpg5, assetOneJpg6, assetOneHeic6],
}),
},
{
should: 'should search by city',
deferred: () => ({ dto: { city: 'Accra' }, assets: [assetHeic] }),
deferred: () => ({
dto: {
city: 'Accra',
includeNull: true,
},
assets: [assetHeic],
}),
},
{
should: "should search city ('')",
deferred: () => ({
dto: {
city: '',
isVisible: true,
includeNull: true,
},
assets: [assetLast],
}),
},
{
should: 'should search city (null)',
deferred: () => ({
dto: {
city: null,
isVisible: true,
includeNull: true,
},
assets: [assetLast],
}),
},
{
should: 'should search by state',
deferred: () => ({ dto: { state: 'New York' }, assets: [assetDensity] }),
deferred: () => ({
dto: {
state: 'New York',
includeNull: true,
},
assets: [assetDensity],
}),
},
{
should: "should search state ('')",
deferred: () => ({
dto: {
state: '',
isVisible: true,
withExif: true,
includeNull: true,
},
assets: [assetLast, assetNotocactus],
}),
},
{
should: 'should search state (null)',
deferred: () => ({
dto: {
state: null,
isVisible: true,
includeNull: true,
},
assets: [assetLast, assetNotocactus],
}),
},
{
should: 'should search by country',
deferred: () => ({ dto: { country: 'France' }, assets: [assetFalcon] }),
deferred: () => ({
dto: {
country: 'France',
includeNull: true,
},
assets: [assetFalcon],
}),
},
{
should: "should search country ('')",
deferred: () => ({
dto: {
country: '',
isVisible: true,
includeNull: true,
},
assets: [assetLast],
}),
},
{
should: 'should search country (null)',
deferred: () => ({
dto: {
country: null,
isVisible: true,
includeNull: true,
},
assets: [assetLast],
}),
},
{
should: 'should search by make',
deferred: () => ({ dto: { make: 'Canon' }, assets: [assetFalcon, assetDenali] }),
deferred: () => ({
dto: {
make: 'Canon',
includeNull: true,
},
assets: [assetFalcon, assetDenali],
}),
},
{
should: 'should search by model',
deferred: () => ({ dto: { model: 'Canon EOS 7D' }, assets: [assetDenali] }),
deferred: () => ({
dto: {
model: 'Canon EOS 7D',
includeNull: true,
},
assets: [assetDenali],
}),
},
{
should: 'should allow searching the upload library (libraryId: null)',
deferred: () => ({
dto: { libraryId: null, size: 1 },
assets: [assetLast],
}),
},
];
@@ -443,32 +537,79 @@ describe('/search', () => {
it('should get suggestions for country', async () => {
const { status, body } = await request(app)
.get('/search/suggestions?type=country')
.get('/search/suggestions?type=country&includeNull=true')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toEqual(countries);
expect(body).toEqual([
'Cuba',
'France',
'Georgia',
'Germany',
'Ghana',
'Japan',
'Morocco',
"People's Republic of China",
'Russian Federation',
'Singapore',
'Spain',
'Switzerland',
'United States of America',
null,
]);
expect(status).toBe(200);
});
it('should get suggestions for state', async () => {
const { status, body } = await request(app)
.get('/search/suggestions?type=state')
.get('/search/suggestions?type=state&includeNull=true')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toHaveLength(states.length);
expect(body).toEqual(expect.arrayContaining(states));
expect(body).toEqual([
'Andalusia',
'Berlin',
'Glarus',
'Greater Accra',
'Havana',
'Île-de-France',
'Marrakesh-Safi',
'Mississippi',
'New York',
'Shanghai',
'St.-Petersburg',
'Tbilisi',
'Tokyo',
'Virginia',
null,
]);
expect(status).toBe(200);
});
it('should get suggestions for city', async () => {
const { status, body } = await request(app)
.get('/search/suggestions?type=city')
.get('/search/suggestions?type=city&includeNull=true')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toEqual(cities);
expect(body).toEqual([
'Accra',
'Berlin',
'Glarus',
'Havana',
'Marrakesh',
'Montalbán de Córdoba',
'New York City',
'Novena',
'Paris',
'Philadelphia',
'Saint Petersburg',
'Shanghai',
'Stanley',
'Tbilisi',
'Tokyo',
null,
]);
expect(status).toBe(200);
});
it('should get suggestions for camera make', async () => {
const { status, body } = await request(app)
.get('/search/suggestions?type=camera-make')
.get('/search/suggestions?type=camera-make&includeNull=true')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toEqual([
'Apple',
@@ -478,13 +619,14 @@ describe('/search', () => {
'PENTAX Corporation',
'samsung',
'SONY',
null,
]);
expect(status).toBe(200);
});
it('should get suggestions for camera model', async () => {
const { status, body } = await request(app)
.get('/search/suggestions?type=camera-model')
.get('/search/suggestions?type=camera-model&includeNull=true')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toEqual([
'Canon EOS 7D',
@@ -499,6 +641,7 @@ describe('/search', () => {
'SM-F711N',
'SM-S906U',
'SM-T970',
null,
]);
expect(status).toBe(200);
});

View File

@@ -15,6 +15,40 @@ describe('/server-info', () => {
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
});
describe('GET /server-info/about', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/server-info/about');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should return about information', async () => {
const { status, body } = await request(app)
.get('/server-info/about')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
version: expect.any(String),
versionUrl: expect.any(String),
repository: 'immich-app/immich',
repositoryUrl: 'https://github.com/immich-app/immich',
build: '1234567890',
buildUrl: 'https://github.com/immich-app/immich/actions/runs/1234567890',
buildImage: 'e2e',
buildImageUrl: 'https://github.com/immich-app/immich/pkgs/container/immich-server',
sourceRef: 'e2e',
sourceCommit: 'e2eeeeeeeeeeeeeeeeee',
sourceUrl: 'https://github.com/immich-app/immich/commit/e2eeeeeeeeeeeeeeeeee',
nodejs: expect.any(String),
ffmpeg: expect.any(String),
imagemagick: expect.any(String),
libvips: expect.any(String),
exiftool: expect.any(String),
licensed: false,
});
});
});
describe('GET /server-info/storage', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/server-info/storage');

View File

@@ -0,0 +1,307 @@
import { LoginResponseDto } from '@immich/sdk';
import { createUserDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
import { app, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, describe, expect, it } from 'vitest';
const serverLicense = {
licenseKey: 'IMSV-6ECZ-91TE-WZRM-Q7AQ-MBN4-UW48-2CPT-71X9',
activationKey:
'4kJUNUWMq13J14zqPFm1NodRcI6MV6DeOGvQNIgrM8Sc9nv669wyEVvFw1Nz4Kb1W7zLWblOtXEQzpRRqC4r4fKjewJxfbpeo9sEsqAVIfl4Ero-Vp1Dg21-sVdDGZEAy2oeTCXAyCT5d1JqrqR6N1qTAm4xOx9ujXQRFYhjRG8uwudw7_Q49pF18Tj5OEv9qCqElxztoNck4i6O_azsmsoOQrLIENIWPh3EynBN3ESpYERdCgXO8MlWeuG14_V1HbNjnJPZDuvYg__YfMzoOEtfm1sCqEaJ2Ww-BaX7yGfuCL4XsuZlCQQNHjfscy_WywVfIZPKCiW8QR74i0cSzQ',
};
describe('/server', () => {
let admin: LoginResponseDto;
let nonAdmin: LoginResponseDto;
beforeAll(async () => {
await utils.resetDatabase();
admin = await utils.adminSetup({ onboarding: false });
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
});
describe('GET /server/about', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/server/about');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should return about information', async () => {
const { status, body } = await request(app)
.get('/server/about')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
version: expect.any(String),
versionUrl: expect.any(String),
repository: 'immich-app/immich',
repositoryUrl: 'https://github.com/immich-app/immich',
build: '1234567890',
buildUrl: 'https://github.com/immich-app/immich/actions/runs/1234567890',
buildImage: 'e2e',
buildImageUrl: 'https://github.com/immich-app/immich/pkgs/container/immich-server',
sourceRef: 'e2e',
sourceCommit: 'e2eeeeeeeeeeeeeeeeee',
sourceUrl: 'https://github.com/immich-app/immich/commit/e2eeeeeeeeeeeeeeeeee',
nodejs: expect.any(String),
ffmpeg: expect.any(String),
imagemagick: expect.any(String),
libvips: expect.any(String),
exiftool: expect.any(String),
licensed: false,
});
});
});
describe('GET /server/storage', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/server/storage');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should return the disk information', async () => {
const { status, body } = await request(app)
.get('/server/storage')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
diskAvailable: expect.any(String),
diskAvailableRaw: expect.any(Number),
diskSize: expect.any(String),
diskSizeRaw: expect.any(Number),
diskUsagePercentage: expect.any(Number),
diskUse: expect.any(String),
diskUseRaw: expect.any(Number),
});
});
});
describe('GET /server/ping', () => {
it('should respond with pong', async () => {
const { status, body } = await request(app).get('/server/ping');
expect(status).toBe(200);
expect(body).toEqual({ res: 'pong' });
});
});
describe('GET /server/version', () => {
it('should respond with the server version', async () => {
const { status, body } = await request(app).get('/server/version');
expect(status).toBe(200);
expect(body).toEqual({
major: expect.any(Number),
minor: expect.any(Number),
patch: expect.any(Number),
});
});
});
describe('GET /server/features', () => {
it('should respond with the server features', async () => {
const { status, body } = await request(app).get('/server/features');
expect(status).toBe(200);
expect(body).toEqual({
smartSearch: false,
configFile: false,
duplicateDetection: false,
facialRecognition: false,
map: true,
reverseGeocoding: true,
oauth: false,
oauthAutoLaunch: false,
passwordLogin: true,
search: true,
sidecar: true,
trash: true,
email: false,
});
});
});
describe('GET /server/config', () => {
it('should respond with the server configuration', async () => {
const { status, body } = await request(app).get('/server/config');
expect(status).toBe(200);
expect(body).toEqual({
loginPageMessage: '',
oauthButtonText: 'Login with OAuth',
trashDays: 30,
userDeleteDelay: 7,
isInitialized: true,
externalDomain: '',
isOnboarded: false,
});
});
});
describe('GET /server/statistics', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/server/statistics');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should only work for admins', async () => {
const { status, body } = await request(app)
.get('/server/statistics')
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
it('should return the server stats', async () => {
const { status, body } = await request(app)
.get('/server/statistics')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
photos: 0,
usage: 0,
usageByUser: [
{
quotaSizeInBytes: null,
photos: 0,
usage: 0,
userName: 'Immich Admin',
userId: admin.userId,
videos: 0,
},
{
quotaSizeInBytes: null,
photos: 0,
usage: 0,
userName: 'User 1',
userId: nonAdmin.userId,
videos: 0,
},
],
videos: 0,
});
});
});
describe('GET /server/media-types', () => {
it('should return accepted media types', async () => {
const { status, body } = await request(app).get('/server/media-types');
expect(status).toBe(200);
expect(body).toEqual({
sidecar: ['.xmp'],
image: expect.any(Array),
video: expect.any(Array),
});
});
});
describe('GET /server/theme', () => {
it('should respond with the server theme', async () => {
const { status, body } = await request(app).get('/server/theme');
expect(status).toBe(200);
expect(body).toEqual({
customCss: '',
});
});
});
describe('GET /server/license', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/server/license');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should only work for admins', async () => {
const { status, body } = await request(app)
.get('/server/license')
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
it('should return the server license', async () => {
await request(app).put('/server/license').set('Authorization', `Bearer ${admin.accessToken}`).send(serverLicense);
const { status, body } = await request(app)
.get('/server/license')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
...serverLicense,
activatedAt: expect.any(String),
});
});
});
describe('DELETE /server/license', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).delete('/server/license');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should only work for admins', async () => {
const { status, body } = await request(app)
.delete('/server/license')
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
it('should delete the server license', async () => {
await request(app)
.delete('/server/license')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send(serverLicense);
const { status } = await request(app).get('/server/license').set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(404);
});
});
describe('PUT /server/license', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put('/server/license');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should only work for admins', async () => {
const { status, body } = await request(app)
.put('/server/license')
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
it('should set the server license', async () => {
const { status, body } = await request(app)
.put('/server/license')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send(serverLicense);
expect(status).toBe(200);
expect(body).toEqual({ ...serverLicense, activatedAt: expect.any(String) });
const { body: licenseBody } = await request(app)
.get('/server/license')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(licenseBody).toEqual({ ...serverLicense, activatedAt: expect.any(String) });
});
it('should reject license not starting with IMSV-', async () => {
const { status, body } = await request(app)
.put('/server/license')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ licenseKey: 'IMCL-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD', activationKey: 'activationKey' });
expect(status).toBe(400);
expect(body.message).toBe('Invalid license key');
});
it('should reject license with invalid activation key', async () => {
const { status, body } = await request(app)
.put('/server/license')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ licenseKey: serverLicense.licenseKey, activationKey: `invalid${serverLicense.activationKey}` });
expect(status).toBe(400);
expect(body.message).toBe('Invalid license key');
});
});
});

View File

@@ -112,6 +112,13 @@ describe('/shared-links', () => {
expect(resp.header['content-type']).toContain('text/html');
expect(resp.text).toContain(`<meta name="description" content="1 shared photos & videos" />`);
});
it('should have fqdn og:image meta tag for shared asset', async () => {
const resp = await request(shareUrl).get(`/${linkWithAssets.key}`);
expect(resp.status).toBe(200);
expect(resp.header['content-type']).toContain('text/html');
expect(resp.text).toContain(`<meta property="og:image" content="http://`);
});
});
describe('GET /shared-links', () => {

View File

@@ -5,6 +5,7 @@ import {
getUserAdmin,
getUserPreferencesAdmin,
login,
updateAssets,
} from '@immich/sdk';
import { Socket } from 'socket.io-client';
import { createUserDto, uuidDto } from 'src/fixtures';
@@ -20,18 +21,16 @@ describe('/admin/users', () => {
let nonAdmin: LoginResponseDto;
let deletedUser: LoginResponseDto;
let userToDelete: LoginResponseDto;
let userToHardDelete: LoginResponseDto;
beforeAll(async () => {
await utils.resetDatabase();
admin = await utils.adminSetup({ onboarding: false });
[websocket, nonAdmin, deletedUser, userToDelete, userToHardDelete] = await Promise.all([
[websocket, nonAdmin, deletedUser, userToDelete] = await Promise.all([
utils.connectWebsocket(admin.accessToken),
utils.userSetup(admin.accessToken, createUserDto.user1),
utils.userSetup(admin.accessToken, createUserDto.user2),
utils.userSetup(admin.accessToken, createUserDto.user3),
utils.userSetup(admin.accessToken, createUserDto.user4),
]);
await deleteUserAdmin(
@@ -64,13 +63,12 @@ describe('/admin/users', () => {
.get(`/admin/users`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(4);
expect(body).toHaveLength(3);
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({ email: admin.userEmail }),
expect.objectContaining({ email: nonAdmin.userEmail }),
expect.objectContaining({ email: userToDelete.userEmail }),
expect.objectContaining({ email: userToHardDelete.userEmail }),
]),
);
});
@@ -81,13 +79,12 @@ describe('/admin/users', () => {
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(5);
expect(body).toHaveLength(4);
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({ email: admin.userEmail }),
expect.objectContaining({ email: nonAdmin.userEmail }),
expect.objectContaining({ email: userToDelete.userEmail }),
expect.objectContaining({ email: userToHardDelete.userEmail }),
expect.objectContaining({ email: deletedUser.userEmail }),
]),
);
@@ -250,18 +247,23 @@ describe('/admin/users', () => {
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
avatar: { color: 'orange' },
memories: { enabled: false },
emailNotifications: { enabled: true, albumInvite: true, albumUpdate: true },
});
expect(body).toMatchObject({ avatar: { color: 'orange' } });
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
expect(after).toEqual({
avatar: { color: 'orange' },
memories: { enabled: false },
emailNotifications: { enabled: true, albumInvite: true, albumUpdate: true },
});
expect(after).toMatchObject({ avatar: { color: 'orange' } });
});
it('should update download archive size', async () => {
const { status, body } = await request(app)
.put(`/admin/users/${admin.userId}/preferences`)
.send({ download: { archiveSize: 1_234_567 } })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({ download: { archiveSize: 1_234_567 } });
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
expect(after).toMatchObject({ download: { archiveSize: 1_234_567 } });
});
});
@@ -294,19 +296,49 @@ describe('/admin/users', () => {
});
it('should hard delete a user', async () => {
const user = await utils.userSetup(admin.accessToken, createUserDto.create('hard-delete-1'));
const { status, body } = await request(app)
.delete(`/admin/users/${userToHardDelete.userId}`)
.delete(`/admin/users/${user.userId}`)
.send({ force: true })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: userToHardDelete.userId,
id: user.userId,
updatedAt: expect.any(String),
deletedAt: expect.any(String),
});
await utils.waitForWebsocketEvent({ event: 'userDelete', id: userToHardDelete.userId, timeout: 5000 });
await utils.waitForWebsocketEvent({ event: 'userDelete', id: user.userId, timeout: 5000 });
});
it('should hard delete a user with stacked assets', async () => {
const user = await utils.userSetup(admin.accessToken, createUserDto.create('hard-delete-1'));
const [asset1, asset2] = await Promise.all([
utils.createAsset(user.accessToken),
utils.createAsset(user.accessToken),
]);
await updateAssets(
{ assetBulkUpdateDto: { stackParentId: asset1.id, ids: [asset2.id] } },
{ headers: asBearerAuth(user.accessToken) },
);
const { status, body } = await request(app)
.delete(`/admin/users/${user.userId}`)
.send({ force: true })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: user.userId,
updatedAt: expect.any(String),
deletedAt: expect.any(String),
});
await utils.waitForWebsocketEvent({ event: 'userDelete', id: user.userId, timeout: 5000 });
});
});

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