* chore: rebase
* chore: open api
* Add Database-Migration for setting targetCodec as acceptedCodec if it was set by admin
* Add TranscodePolicy setting, to only transcode files with a bitrate higher than set max bitrate
* Rename enum value of TranscodePolicy
* calculate max_bitrate according to "k" and "m" suffix for comparison
* remove migration
* minor changes
* UnitTest for Bitrate Policy
* Fix UnitTest
* Add missing output options
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
* Adding memory epilogue card
* Adds epilogue page to memories
* Fixes a next / back issue
* color
---------
Co-authored-by: Alex <alex.tran1502@gmail.com>
* added a configuration option to select the dri node in transcoding
* chore: open api
* refactor: get hawrdware device
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* feat: search peoples
* fix: responsive design
* use existing count
* generate sql file
* fix: tests
* remove visible people
* fix: merge, hide...
* use component
* fix: linter
* chore: regenerate api
* fix: change name when searching for a face
* save search
* remove duplicate
* use enums for query parameters
* fix: increase to 20 for the local search
* use constants
* simplify
* fix: number of people more visible
* fix: merge
* fix: search
* fix: loading spinner position
* pr feedback
install.sh: fix bash error
Error 1:
./install.sh: 26: [[: not found
Error 2:
docker: 'compose' is not a docker command.
Signed-off-by: Peppe289 <gsperanza204@protonmail.com>
* Documentation corrections
* fix import
* add firewall note
* npm run format:fix
* fixs
* npm run format:fix
* space
* fix note
* admin-jobs.png image update + fixes
* Storage Template.md update
* Add new Troubleshooting about symbolic link in library
* Updating the libraries.md
* Updating the libraries.md
* Corrections
* add `/`
* ...
* Add Python script to remove-offline-files.md
* npm run format:fix
* Add info about HDR in FAQ
* My wrong merge
* add info about symlink
* [Community] + PowerShell
* add 360 photo support to Features in README
* add info about remote ML and info about orphaned files from the external library to the scripts page
* Typo
* add note about storage locations
* add info about Purge for portainer and link to info about asset types and storage locations
* npm run format:fix
* Add FAQ about "faces" that aren't faces
* Update docs/docs/administration/backup-and-restore.md
* Update docs/docs/administration/backup-and-restore.md
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* Blocking multiple downloads
* Blocking the download based on file name and not download type
* Fixing failing workflow
* Make sure the uniqueDownloadId is unique even if the selecting order is different
* Using DateTime from luxon & convering the case of downloading an album
* Fixing typo in the warning.
* Covering the case where tha list of assets is to big
* Fix format
* Fix format
* Fix format
* Undo block multi-downloads
* Running format:fix
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* Fix extraction of samsung motionphoto videos
* Refactor binary tag extraction to the repository to consolidate exiftool usage
* format
* fix linting and swap argument orders
* Fix tag name and conditional order
* Add unit test
* Update server test assets submodule
* Remove old motion photo video assets when a new one is extracted
* delete first, then write
* Include motion photo asset uuid's in the filename
If the filenames are not uniquified, then we can't delete old/corrupt ones
* Fix formatting and fix/add tests
* chore: only use new uuid
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Other modals throughout the web app close when the user
presses the escape key, clicks outside the modal, or on
the close button. Modals from the user management page
missed the escape key functionality. This change makes
the behavior more consistent across all views.
* feat(mobile): delete assets from device only
* mobile: add backed up only toggle for delete device only
* remove toggle inside alert and show different content
* mobile: change content color for local only
* mobile: delete local only button to dialog
* style: display bottom action in two lines
* feat: separate delete buttons
* fix: incorrect error message for ownedRemoteSelection
* feat(mobile): long-press delete to permanently delete asset
* chore: add todo to handle long press to delete in gallery_viewer
* chore: rebase on deletion branch
* feat(mobile): long-press delete to permanently delete asset
* fix(mobile): update minChildSize of control bottom app bar
---------
Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
* fix(mobile): handle asset removal state from trash for merged assets
* fix(mobile): use appropriate text for trash / delete
---------
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
* Feat: provide the ability to search archived photos
Adds a query parameter (`searchArchived`) to the search URL parameters
to allow the results to contain archived photos.
* chore: rename includeArchived => withArchived
* chore: open api
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* feat(mobile): delete assets from device only
* mobile: add backed up only toggle for delete device only
* remove toggle inside alert and show different content
* mobile: change content color for local only
* mobile: delete local only button to dialog
* style: display bottom action in two lines
* feat: separate delete buttons
* fix: incorrect error message for ownedRemoteSelection
* fix: handle remoteOnly from delete everywhere
* request confirmation for local only only when non-backed assets are in selection
---------
Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
Fixes https://github.com/immich-app/immich/issues/5982.
There are basically three options:
1. Search `originalFileName` by dropping a file extension from the query
(if present). Lower fidelity but very easy - just a standard index &
equality.
2. Search `originalPath` by adding an index on `reverse(originalPath)`
and using `starts_with(reverse(query) + "/", reverse(originalPath)`. A
weird index & query but high fidelity.
3. Add a new generated column called `originalFileNameWithExtension` or
something. More storage, kinda jank.
TBH, I think (1) is good enough and easy to make better in the future.
For example, if I search "DSC_4242.jpg", I don't really think it matters
if "DSC_4242.mov" also shows up.
edit: There's a fourth approach that we discussed a bit in Discord and
decided we could switch to it in the future: using a GIN. The minor
issue is that Postgres doesn't tokenize paths in a useful (they're a
single token and it won't match against partial components). We can
solve that by tokenizing it ourselves. For example:
```
immich=# with vecs as (select to_tsvector('simple', array_to_string(string_to_array('upload/library/sushain/2015/2015-08-09/IMG_275.JPG', '/'), ' ')) as vec) select * from vecs where vec @@ phraseto_tsquery('simple', array_to_string(string_to_array('library/sushain', '/'), ' '));
vec
-------------------------------------------------------------------------------
'-08':6 '-09':7 '2015':4,5 'img_275.jpg':8 'library':2 'sushain':3 'upload':1
(1 row)
```
The query is also tokenized with the 'split-by-slash-join-with-space'
strategy. This strategy results in `IMG_275.JPG`, `2015`, `sushain` and
`library/sushain` matching. But, `08` and `IMG_275` do not match. The
former is because the token is `-08` and the latter because the
`img_275.jpg` token is matched against exactly.
* chore(web): quota enhancement
* show quota in user table
* update quota for single user ioption
* Add a note how to set unlimited storage
* fixed deletion doesn't update quota
* refactor relation
* fixed test
* re-refactor
* update sql
* fix e2e test
* Update server/src/domain/user/user.service.ts
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* revert e2e test
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* Update added and re -arrangement of FAQ
* Erasure of addition mistakes
* Erasure of addition mistakes
* Fix broken links
* Correcting spelling errors + adding more questions
* New required fixes
* More FAQ
* Adding questions + adding a note about a directory and an explanation about adding a path in a Windows environment
* Update docs/docs/FAQ/Albums-FAQ.md
Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
* Update docs/docs/FAQ/Assets-FAQ.md
Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
* Update docs/docs/FAQ/Machine-Learning-FAQ.md
Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
* Update docs/docs/FAQ/Machine-Learning-FAQ.md
Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
* Update docs/docs/features/libraries.md
Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
* Corrections
* chore: updates
* import TOCinlines from all FAQ pages to one page + Corrections
* Removing privacy information + adding required Flutter version information
* Removing privacy information + adding required Flutter version information
* Revert "Removing privacy information + adding required Flutter version information"
This reverts commit da63439fd2.
* All in one page
* Guide - Remove Offline Files
* Guide - Remove Offline Files
* doc: updates
* chore: fix broken link
* docs: clean up database gui guide
---------
Co-authored-by: Alex <alex.tran1502@gmail.com>
Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* refactor admin settings
* use slots to render buttons in simplified template settings
* remove more boilerplate by looping over components
* fix: onboarding
* fix: reset/reset to default
* remove lodash since it is unecessary
* chore: standardize padding and margins
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* fix: grid on people page
* pr feedback
* wait before width is set
* fix: animation
* fix: use grid instead
---------
Co-authored-by: Alex <alex.tran1502@gmail.com>
* fix(server): Split database queries based on PostgreSQL bound params limit
PostgreSQL uses a 16-bit integer to indicate the number of bound
parameters.
This means that the maximum number of parameters for any query is 65535.
Any query that tries to bind more than that (e.g. searching by a list of
IDs) requires splitting the query into multiple chunks.
This change includes refactoring every Repository that runs queries
using a list of ids, and either flattening or merging results.
Fixes#5788, #5997.
Also, potentially a fix for #4648 (at least based on
[this comment](https://github.com/immich-app/immich/issues/4648#issuecomment-1826134027)).
References:
* https://github.com/typeorm/typeorm/issues/7565
* [PostgreSQL message format - Bind](https://www.postgresql.org/docs/15/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-BIND)
* misc: Create Chunked decorator to simplify implementation
* feat: Add ChunkedArray/ChunkedSet decorators
* feat(server): Throw error when PostgreSQL version is not within the supported versions
The pgvecto.rs extension, though not distributed, can be built for PostgreSQL 12 and 13.
An installation of PostgreSQL 12 with the pgvecto.rs extensions installed will not be caught by immich.
This causes immich to attempt to run the database migrations without having a proper environment.
With assertPostgresql the server will throw an error if the PostgreSQL version is not within the supported range.
* Replaced assertion with lesser than comparison
As requested by @zackpollard
* Changed the comparison to use the minPostgresVersion variable.
If we define one we might as well use it. makes changing the versioning later easier
* Added two new tests, modified two existing tests
`should return if minimum supported PostgreSQL and vectors version are installed`:
Check if init returns properly and that getPostgresVersion is called twice
`should thrown an error if PostgreSQL version is below minimum supported version`:
Checks if the init function correctly returns an error
`should suggest image with postgres ${major} if database is ${major}`:
Modified to set MockResolvedValue instead of MockResolvedValueOnce. With the new check we get the PostgreSQL version twice. So it needs to be set during the entire test.
`should not suggest image if postgres version is not in 14, 15 or 16`:
Modified the bounds to [14, 18]. Because values below 14 now will not get called.
Also Modified to call `getPostgresVersion.MockResolvedValueOnce` for twice, because it gets called twice.
* Fixed two mistakes in the jest functions from previous commit #2abcb60
`should thrown an error if PostgreSQL version is below minimum supported version`:
The regex function I wrote mistakingly used the negate function which check that the error *did not* contain the phrase "PostgreSQL". Which is the opposite
`should not suggest image if postgres version is not in 14, 15 or 16`:
confused bounds for a normal javascript array. Changed the test to only check for values above 16. As values below 14 will get thrown out by test `should return if minimum supported PostgreSQL and vectors version are installed`
I apologise for the mistakes in my previous commit.
* Format fix
---------
Co-authored-by: max <wak@vanling.net>
The current `removeAsset` implementation just builds the query but does
not execute it. That also seems to be the reason the `@GenerateSql`
decorator was commented out.
* feat(web): onboarding
* feat: openapi
* feat: modulization
* feat: page advancing
* Animation
* Add storage templaete settings
* sql
* more style
* Theme
* information and styling
* hide/show table
* Styling
* Update user property
* fix test
* fix test:
* fix e2e
* test
* Update web/src/lib/components/onboarding-page/onboarding-hello.svelte
Co-authored-by: bo0tzz <git@bo0tzz.me>
* naming
* use System Metadata
* better return type
* onboarding using server metadata
* revert previous changes in user entity
* sql
* test web
* fix test server
* server/web test
* more test
* consolidate color theme change logic
* consolidate save button to storage template
* merge main
* fix web
---------
Co-authored-by: bo0tzz <git@bo0tzz.me>
* fix(deps): update dependency @nestjs/schedule to v4
* fix: change CronJob in addCronJob to match new type required by nestjs schedule module
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
* Update libraries.md - External Library step by step set up guide added
When setting up immmich external libraries, I found some missing details around the relationship between external paths and import paths. By providing an example, I am hoping it helps new users.
* chore: fix formatting
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* Update hardware-transcoding.md
I accidentally closed#5924 for some odd reason. Copied the same code changes to this one.
* updated formatting
* Update hardware-transcoding.md
Added line 66 saying that `NVIDIA_DRIVER_CAMPABILITITES` is no longer required.
* feat(server): Enqueue jobs in bulk
The Job Repository now has a `queueAll` method, that enqueues messages
in bulk (using BullMQ's
[`addBulk`](https://docs.bullmq.io/guide/queues/adding-bulks)),
improving performance when many jobs must be enqueued within the same
operation.
Primary change is in `src/domain/job/job.service.ts`, and other services
have been refactored to use `queueAll` when useful.
As a simple local benchmark, triggering a full thumbnail generation
process over a library of ~1,200 assets and ~350 faces went from
**~600ms** to **~250ms**.
* fix: Review feedback
* fix(docs): update broken link
* fix(docs): change to path
* fix(docs): second broken link
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* Updated vite and ts config file with vtest options and a new alias to fix the dev command error
* Updated package script and update the packages
-- this removes jest dependencies
* Added new setup file needed in vitest in order to be able to use the jest-dom matchers in tests
* Updated deprecated utilities when using faker
* Updated test files and mocks to use vitest instead of jest
* Enabled web test check in GitHub actions
* remove babel dependencies as they are no longer needed with vitest
* move the jest config files to a folder in case we need to go back to jest
* chore: remove old files
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* fix: locks need to be acquired and released using the same session
* feat: only allow a single storage template operation at a single time
this has been added to avoid possible rare race conditions where two files are moved at once to the same path with the same name, causing our duplicate iterator to not detect them and therefore both files will have the same name and overwrite eachother
* fix: pgvecto.rs extension breaks typeorm schema:drop command
* fix: parse postgres bigints to javascript number types when selecting data
* feat: verify file size is the same as original asset after copying file for storage template job
* feat: allow disabling of storage template job, defaults to disabled for new instances
* fix: don't allow setting concurrency for storage template migration, can cause race conditions above 1
* feat: add checksum verification when file is copied for storage template job
* fix: extract metadata for assets that aren't visible on timeline
* fix(server): Reduce number of bound parameters in Access queries
According to https://github.com/typeorm/typeorm/issues/7565, the
introduction of bulk queries for permission checks could quickly reach
the limit of 65536 bound parameters allowed by the PostgreSQL
connection.
To avoid reaching that limit, this first change refactors the Access
queries that are expanding the set of ids multiple times. For example,
`asset.checkSharedLinkAccess` expands the ids 4 times, so providing just
~16400 ids is enough to break the query.
Refactored queries:
* activity.checkCreateAccess
```sql
-- Before
SELECT "AlbumEntity"."id" AS "AlbumEntity_id"
FROM "albums" "AlbumEntity"
LEFT JOIN "albums_shared_users_users" "AlbumEntity_AlbumEntity__AlbumEntity_sharedUsers"
ON "AlbumEntity_AlbumEntity__AlbumEntity_sharedUsers"."albumsId"="AlbumEntity"."id"
LEFT JOIN "users" "AlbumEntity__AlbumEntity_sharedUsers"
ON "AlbumEntity__AlbumEntity_sharedUsers"."id"="AlbumEntity_AlbumEntity__AlbumEntity_sharedUsers"."usersId"
AND ("AlbumEntity__AlbumEntity_sharedUsers"."deletedAt" IS NULL)
WHERE
(
(
"AlbumEntity"."id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
AND "AlbumEntity"."isActivityEnabled" = $11
AND "AlbumEntity__AlbumEntity_sharedUsers"."id" = $12
)
OR (
"AlbumEntity"."id" IN ($13, $14, $15, $16, $17, $18, $19, $20, $21, $22)
AND "AlbumEntity"."isActivityEnabled" = $23
AND "AlbumEntity"."ownerId" = $24
)
)
AND "AlbumEntity"."deletedAt" IS NULL
-- After
SELECT "album"."id" AS "album_id"
FROM "albums" "album"
LEFT JOIN "albums_shared_users_users" "album_sharedUsers"
ON "album_sharedUsers"."albumsId"="album"."id"
LEFT JOIN "users" "sharedUsers"
ON "sharedUsers"."id"="album_sharedUsers"."usersId"
AND "sharedUsers"."deletedAt" IS NULL
WHERE
"album"."id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
AND "album"."isActivityEnabled" = true
AND (
"album"."ownerId" = $11
OR "sharedUsers"."id" = $12
)
AND "album"."deletedAt" IS NULL
```
* asset.checkAlbumAccess
```sql
-- Before
SELECT
"asset"."id" AS "assetId",
"asset"."livePhotoVideoId" AS "livePhotoVideoId"
FROM "albums" "album"
INNER JOIN "albums_assets_assets" "album_asset"
ON "album_asset"."albumsId"="album"."id"
INNER JOIN "assets" "asset"
ON "asset"."id"="album_asset"."assetsId"
AND "asset"."deletedAt" IS NULL
LEFT JOIN "albums_shared_users_users" "album_sharedUsers"
ON "album_sharedUsers"."albumsId"="album"."id"
LEFT JOIN "users" "sharedUsers"
ON "sharedUsers"."id"="album_sharedUsers"."usersId"
AND "sharedUsers"."deletedAt" IS NULL
WHERE
(
"album"."ownerId" = $1
OR "sharedUsers"."id" = $2
)
AND (
"asset"."id" IN ($3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
OR "asset"."livePhotoVideoId" IN ($13, $14, $15, $16, $17, $18, $19, $20, $21, $22)
)
AND "album"."deletedAt" IS NULL
-- After
WITH "assetIds" AS (
SELECT unnest(array[$1, $2, $3, $4, $5, $6, $7, $8, $9, $10])::uuid AS "id"
FROM (SELECT 1 AS dummy_column) "dummy_table"
)
SELECT
"asset"."id" AS "assetId",
"asset"."livePhotoVideoId" AS "livePhotoVideoId"
FROM "albums" "album"
INNER JOIN "albums_assets_assets" "album_asset"
ON "album_asset"."albumsId"="album"."id"
INNER JOIN "assets" "asset"
ON "asset"."id"="album_asset"."assetsId"
AND "asset"."deletedAt" IS NULL
LEFT JOIN "albums_shared_users_users" "album_sharedUsers"
ON "album_sharedUsers"."albumsId"="album"."id"
LEFT JOIN "users" "sharedUsers"
ON "sharedUsers"."id"="album_sharedUsers"."usersId"
AND "sharedUsers"."deletedAt" IS NULL
WHERE
(
"album"."ownerId" = $11
OR "sharedUsers"."id" = $12
)
AND (
"asset"."id" IN (SELECT id FROM "assetIds")
OR "asset"."livePhotoVideoId" IN (SELECT id FROM "assetIds")
)
AND "album"."deletedAt" IS NULL
```
* asset.checkSharedLinkAccess
```sql
-- Before
SELECT
"assets"."id" AS "assetId",
"assets"."livePhotoVideoId" AS "assetLivePhotoVideoId",
"albumAssets"."id" AS "albumAssetId",
"albumAssets"."livePhotoVideoId" AS "albumAssetLivePhotoVideoId"
FROM "shared_links" "sharedLink"
LEFT JOIN "albums" "album"
ON "album"."id"="sharedLink"."albumId"
AND "album"."deletedAt" IS NULL
LEFT JOIN "shared_link__asset" "assets_sharedLink"
ON "assets_sharedLink"."sharedLinksId"="sharedLink"."id"
LEFT JOIN "assets" "assets"
ON "assets"."id"="assets_sharedLink"."assetsId"
AND "assets"."deletedAt" IS NULL
LEFT JOIN "albums_assets_assets" "album_albumAssets"
ON "album_albumAssets"."albumsId"="album"."id"
LEFT JOIN "assets" "albumAssets"
ON "albumAssets"."id"="album_albumAssets"."assetsId"
AND "albumAssets"."deletedAt" IS NULL
WHERE
"sharedLink"."id" = $1
AND (
"assets"."id" IN ($2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
OR "albumAssets"."id" IN ($12, $13, $14, $15, $16, $17, $18, $19, $20, $21)
OR "assets"."livePhotoVideoId" IN ($22, $23, $24, $25, $26, $27, $28, $29, $30, $31)
OR "albumAssets"."livePhotoVideoId" IN ($32, $33, $34, $35, $36, $37, $38, $39, $40, $41)
)
-- After
WITH "assetIds" AS (
SELECT unnest(array[$1, $2, $3, $4, $5, $6, $7, $8, $9, $10])::uuid AS "id"
FROM (SELECT 1 AS dummy_column) "dummy_table"
)
SELECT
"assets"."id" AS "assetId",
"assets"."livePhotoVideoId" AS "assetLivePhotoVideoId",
"albumAssets"."id" AS "albumAssetId",
"albumAssets"."livePhotoVideoId" AS "albumAssetLivePhotoVideoId"
FROM "shared_links" "sharedLink"
LEFT JOIN "albums" "album"
ON "album"."id"="sharedLink"."albumId"
AND "album"."deletedAt" IS NULL
LEFT JOIN "shared_link__asset" "assets_sharedLink"
ON "assets_sharedLink"."sharedLinksId"="sharedLink"."id"
LEFT JOIN "assets" "assets"
ON "assets"."id"="assets_sharedLink"."assetsId"
AND "assets"."deletedAt" IS NULL
LEFT JOIN "albums_assets_assets" "album_albumAssets"
ON "album_albumAssets"."albumsId"="album"."id"
LEFT JOIN "assets" "albumAssets"
ON "albumAssets"."id"="album_albumAssets"."assetsId"
AND "albumAssets"."deletedAt" IS NULL
WHERE
"sharedLink"."id" = $11
AND (
"assets"."id" IN (SELECT id FROM "assetIds")
OR "albumAssets"."id" IN (SELECT id FROM "assetIds")
OR "assets"."livePhotoVideoId" IN (SELECT id FROM "assetIds")
OR "albumAssets"."livePhotoVideoId" IN (SELECT id FROM "assetIds")
)
```
* fix: Use array overlapping instead of CTEs
* fix(mobile): Load assets on "Live-Images" page
Instead of requesting the server for the relevant entries, we can use
the local DB.
This change fixes loading errors when going to the "Live-Images" page.
It is similar to the work done with #5971.
* fix(mobile): Fix Recently added page
included all thumbnail metadata. It seems this has to be explicitly disabled.
Refs: #4382
feat. basic metadata e2e test
fix: use tiff thumbnails in first step + e2e fix
fix: revert switch to tiff
feat: test metadata of both webp and jpg
feat: use upload in e2e test
fix: lint
strip metadata with exiftool
use `withIccProfile`
fix e2e
formatting
run jobs in e2e
| Выгрузка на сервер и просмотр видео и фото | Да | Да |
| Авто бекап когда приложение открыто | Да | Н/Д |
| Выбор альбома(ов) для бекапа | Да | Н/Д |
| загрузка с сервера фото и видео на устройство | Да | Да |
| Поддержка нескольких пользователей | Да | Да |
| Альбомы и общие альбомы | Да | Да |
| Прокручиваемая/перетаскиваемая полоса прокрутки | Да | Да |
| Поддержка формата RAW | Да | Да |
| Просмотр метаданных (EXIF, map) | Да | Да |
| Поиск до метаданным, объектам, лицам и CLIP | Да | Да |
| Административные функци (управление пользователями) | Нет | Да |
| Фоновый бекпа | Да | Н/Д |
| Виртуальная прокрутка | Да | Да |
| Поддержка OAuth | Да | Да |
| Ключи API | Н/Д | Да |
| LivePhoto/MotionPhoto бекап и воспроизведение | Да | Да |
| Настраиваемая структура хранилища | Да | Да |
| Публичные альбомы | Нет | Да |
| Архив и Избранное | Да | Да |
| Мировая карта | Да | Да |
| Совместное использование | Да | Да |
| Распознавание лиц и группировка по лицам | Да | Да |
| В этот день (x лет назад) | Да | Да |
| Работа без интернета | Да | Нет |
| Галлереи только для просмотра | Да | Да |
| Колллажи | Да | Да |
## Поддержка проекта
Я посвятил себя этому проекту и не остановлюсь. Я буду продолжать обновлять документацию, добавлять новые функции и исправлять ошибки. Но я не могу сделать это один. Поэтому мне нужна ваша помощь, чтобы дать мне дополнительную мотивацию продолжать идти дальше.
Как сказали наши покровители [selfhosted.show - In the episode 'The-organization-must-not-be-name is a Hostile Actor'](https://selfhosted.show/79?t=1418), это масштабная работа, которую мы с командой делаем. И мне бы очень хотелось когда-нибудь иметь возможность заниматься этим на постоянной основе, и я прошу вашей помощи, чтобы это произошло.
Если вы считаете, что это правильная причина и вы уже давно используете это приложение, рассмотрите возможность финансовой поддержки проекта, выбрав вариант ниже.
### Пожертвование
- [Ежемесячное пожертвование](https://github.com/sponsors/immich-app) via GitHub Sponsors
- [Одноразовое пожертвование](https://github.com/sponsors/immich-app?frequency=one-time&sponsor=alextran1502) via GitHub Sponsors
就像我在 [selfhosted.show - In the episode 'The-organization-must-not-be-name is a Hostile Actor'](https://selfhosted.show/79?t=1418) 节目里说的一样,这是我和团队的一项艰巨任务。并且我希望某一天我能够全职开发本项目,在此我请求您能够助我梦想成真。
就像我在 [selfhosted.show - In the episode 'The-organization-must-not-be-name is a Hostile Actor'](https://selfhosted.show/79?t=1418) 节目里说的一样,这是我和团队的一项艰巨任务。并且我希望某一天我能够全职开发本项目,在此我请求您能够助我梦想成真。
|  | Asset is only available in the cloud and was uploaded from some other device (like the web client) or was deleted from this device after upload |
|  | Asset is only available locally and has not yet been backed up |
|  | Asset was uploaded from this device and is now backed up in the cloud/server and still available in original on the device |
### Can I add my existing photo library?
Yes, with an [external library](/docs/features/libraries.md).
### Why are only photos and not videos being uploaded to Immich?
This often happens when using a reverse proxy or cloudflare tunnel in front of Immich. Make sure to set your reverse proxy to allow large POST requests. In `nginx`, set `client_max_body_size 50000M;` or similar. Cloudflare tunnels are limited to 100 mb file sizes. Also check the disk space of your reverse proxy, in some cases proxies caches requests to disk before passing them on, and if disk space runs out the request fails.
### 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#how-can-i-lower-immichs-cpu-usage) this or [disable](/docs/FAQ.md#how-can-i-disable-machine-learning) machine learning entirely.
### How can I lower Immich's CPU usage?
The initial backup is the most intensive due to the number of jobs running. The most CPU-intensive ones are transcoding and machine learning jobs (Tag Images, Smart Search, Recognize Faces), and to a lesser extent thumbnail generation. Here are some ways to lower their CPU usage:
- 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.
- You _must_ re-run the Recognize Faces job for all images after this for facial recognition on new images to work properly.
- If these changes are not enough, see [below](/docs/FAQ.md#how-can-i-disable-machine-learning) for how you can disable machine learning.
### How can I disable machine learning?
:::info
Disabling machine learning will result in a poor experience for searching and the 'Explore' page, as these are reliant on it to work as intended.
:::
Machine learning can be disabled under Settings > Machine Learning Settings, either entirely or by model type. For instance, you can choose to disable smart search with CLIP, but keep facial recognition enabled. This means that the machine learning service will only process the enabled jobs.
However, disabling all jobs will not disable the machine learning service itself. To prevent it from starting up at all in this case, you can comment out the `immich-machine-learning` section of the docker-compose.yml.
### I'm getting errors about models being corrupt or failing to download. What do I do?
You can delete the model cache volume, which is where models are downloaded. This will give the service a clean environment to download the model again.
### What happens to existing files after I choose a new [Storage Template](/docs/administration/storage-template.mdx)?
Template changes will only apply to new assets. To retroactively apply the template to previously uploaded assets, run the Storage Migration Job, available on the [Jobs](/docs/administration/jobs.md) page.
### In the uploads folder, why are photos stored in the wrong date?
This is fixed by running the storage migration job.
### Why are there so many thumbnail generation jobs?
Immich generates three thumbnails for each asset (blurred, small, and large), as well as a thumbnail for each recognized face.
### How can I see Immich logs?
Most 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 run Immich as a non-root user?
1. Set the `PUID`/`PGID` environment variables (in `.env`).
2. Set the corresponding `user` argument in `docker-compose` for each service.
3. Add an additional volume to `immich-microservices` that mounts internally to `/usr/src/app/.reverse-geocoding-dump`.
The non-root user/group needs read/write access to the volume mounts, including `UPLOAD_LOCATION`.
### How can I reset the admin password?
The admin password can be reset by running the [reset-admin-password](/docs/administration/server-commands.md) command on the immich-server.
### How can I backup data from Immich?
See [backup and restore](/docs/administration/backup-and-restore.md).
### How can I **purge** data from Immich?
Data for Immich comes in two forms:
1.**Metadata** stored in a postgres database, persisted via the `pg_data` volume
2.**Files** (originals, thumbs, profile, etc.), stored in the `UPLOAD_LOCATION` folder.
To remove the **Metadata** you can stop Immich and delete the volume.
```bash title="Remove Immich (containers and volumes)"
docker-compose down -v
```
After removing the containers and volumes, the **Files** can be cleaned up (if necessary) from the `UPLOAD_LOCATION` by simply deleting an unwanted files or folders.
### How can I move all data (photos, persons, albums) from one user to another?
This requires some database queries. 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.
:::warning
This is an advanced operation. If you can't to do it with the steps described here, this is not for you.
:::
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. Three tables need to be updated:
```sql
// 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>');
```
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.
|  | Asset is only available in the cloud and was uploaded from some other device (like the web client) or was deleted from this device after upload |
|  | Asset is only available locally and has not yet been backed up |
|  | Asset was uploaded from this device and is now backed up to the server; the original file is still on the device |
### I cannot log into the application after an update. What can I do?
First, verify that the mobile app and server are both running the same version (major and minor).
:::note
App store updates sometimes take longer because the stores (play store; Google and app store; Apple)
need to approve the update first which may take some time.
:::
If you still cannot login to the app, try the following:
- Check the mobile logs
- Make sure login credentials are correct by logging in on the web app
---
## Assets
### Can I add my existing photo library?
Yes, with an [External Library](/docs/features/libraries.md).
### What happens to existing files after I choose a new [Storage Template](/docs/administration/storage-template.mdx)?
Template changes will only apply to _new_ assets. To retroactively apply the template to previously uploaded assets, run the Storage Migration Job, available on the [Jobs](/docs/administration/jobs.md) page.
### Why are only photos and not videos being uploaded to Immich?
This often happens when using a reverse proxy (such as nginx or Cloudflare tunnel) in front of Immich. Make sure to set your reverse proxy to allow large `POST` requests. In `nginx`, set `client_max_body_size 50000M;` or similar. Also check the disk space of your reverse proxy, in some cases proxies cache requests to disk before passing them on, and if disk space runs out the request fails.
### Why are some photos stored in the file system with the wrong date?
There are a few different scenarios that can lead to this situation. The solution is to simply run the storage migration job again. The job is only _automatically_ run once per asset, after upload. If metadata extraction originally failed, the jobs were cleared/cancelled, etc. the job may not have run automatically the first time.
### How can I hide photos from the timeline?
You can _archive_ them.
### How can I backup data from Immich?
See [Backup and Restore](/docs/administration/backup-and-restore.md).
### Does Immich support reading existing face tag metadata?
No, it currently does not.
### Does Immich support filtering of NSFW images?
No, it currently does not, but there is an [open discussion about it On Github](https://github.com/immich-app/immich/discussions/2451). You can submit a pull request or vote for the discussion.
### Why are there so many thumbnail generation jobs?
There are three thubmanil jobs for each asset:
- Blurred (thumbhash)
- Small (webp)
- Large (jpeg)
Also, there are additional jobs for person (face) thumbnails.
### What happens if an asset exists in more than one account?
There are no requirements for assets to be unique across users. If multiple users upload the same image they are processed as if they were distinct assets and jobs run and thumbnails are generated accordingly.
### Why do HDR videos appear pale in Immich player but look normal after download?
Immich uses a player with known HDR color display issues. We are experimenting with a different player that provides better color profiles for HDR content for future improvements.
### How can I delete transcoded videos without deleting the original?
The transcode of an asset can be deleted by setting a transcode policy that makes it unnecessary, then running a transcoding job for that asset. This can be done on a per-asset basis by starting a transcoding job for an asset (with the _Refresh encoded videos_ button in the asset viewer options. Or, for all assets by running transcoding jobs for all assets.
To update the transcode policy, navigate to Administration > Video Transcoding Settings > Transcoding Policy and select a policy from the drop-down. This policy will determine whether an existing transcode will be deleted or overwritten in the transcoding job. If a video should be transcoded according to this policy, an existing transcode is overwritten. If not, then it is deleted.
:::note
For example, say you have existing transcodes with the policy "Videos higher than normal resolution or not in the desired format" and switch to a narrower policy: "Videos not in the desired format". If an asset was only transcoded due to its resolution, then running a transcoding job for it will now delete the existing transcode. This is because resolution is no longer part of the transcode policy and the transcode is unnecessary as a result. Likewise, if you set the policy to "Don't transcode any videos" and run transcoding jobs for all assets, this will delete all existing transcodes as they are all unnecessary.
:::
### Is it possible to compress images during backup?
No. Our golden rule is that the original assets should always be untouched, so we don't think this feature is a good fit for Immich.
### How can I move all data (photos, persons, albums) 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.
:::warning
This is an advanced operation. If you can't do it with the steps described here, this is not for you.
:::
<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. Three tables need to be updated:
```sql
// 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>');
```
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
### Can I keep my existing album structure while importing assets into Immich?
Yes. You can by use [Immich CLI](/docs/features/command-line-interface) along with the `--album` flag.
### Is there a way to reorder photos within an album?
No, not yet. For updates on this planned feature, follow the [GitHub discussion](https://github.com/immich-app/immich/discussions/1689),
---
## External Library
### Can I add an external library while keeping the existing albums structure?
We haven't put in an official mechanism to create albums from external libraries at the moment., but there are some [workarounds from the community](https://github.com/immich-app/immich/discussions/4279) which you can find here to help you achieve that.
### What happens to duplicates in external libraries?
Duplicate checking only exists for upload libraries, using the file hash. Furthermore, duplicate checking is not global, but _per library_. Therefore, a situation where the same file appears twice in the timeline is possible, especially for external libraries.
---
## Machine Learning
### How does smart search work?
Immich uses CLIP models, for more information about CLIP and its capabilities read about it [here](https://openai.com/research/clip).
### How does facial recognition work?
For face detection and recognition, Immich uses [InsightFace models](https://github.com/deepinsight/insightface/tree/master/model_zoo).
### How can I disable machine learning?
:::info
Disabling machine learning will result in a poor experience for searching and the 'Explore' page, as these are reliant on it to work as intended.
:::
Machine learning can be disabled under Administration > Settings > Machine Learning Settings, either entirely or by model type. For instance, you can choose to disable smart search with CLIP, but keep facial recognition enabled. This means that the machine learning service will only process the enabled jobs.
However, disabling all jobs will not disable the machine learning service itself. To prevent it from starting up at all in this case, you can comment out the `immich-machine-learning` section of the docker-compose.yml.
### I'm getting errors about models being corrupt or failing to download. What do I do?
You can delete the model cache volume, which is where models are downloaded to. This will give the service a clean environment to download the model again.
### Why did Immich decide to remove object detection?
The feature added keywords to images for metadata search, but wasn't used for smart search. Smart search made it unnecessary as it isn't limited to exact keywords. Combined with it causing crashes on some devices, using many dependencies and causing user confusion as to how search worked, it was better to remove the job altogether.
For more info see [here](https://github.com/immich-app/immich/pull/5903)
### Can I use a custom CLIP model?
No, this is not supported. Only models listed in the [Huggingface](https://huggingface.co/immich-app) 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](https://huggingface.co/immich-app).
:::
### Does Immich support Facial Recognition for videos ?
This is not currently implemented, but may be in the future.
On the other hand, Immich does scan video thumbnails for faces, so it can perform recognition if the face is clear in the video thumbnail.
### Does Immich have animal recognition?
No.
### I'm getting a lot of "faces" that aren't faces, what can I do?
You can increase the MIN DETECTION SCORE to 0.8 to help prevent bad thumbnails. However, a score of 0.9 might filter out too many real faces depending on the library used. If you just want to hide specific faces, you can adjust the 'MIN FACES DETECTED' setting in the administration panel
to increase the bar for what the algorithm considers a "core face" for that person, reducing the chance of bad thumbnails being chosen.
### The immich_model-cache volume takes up a lot of space, what could be the problem?
If you installed several models and chose not to use some of them, it might be worth deleting the old models that are in immich_model-cache.
To do this you can run:
- `docker run -it --rm -v immich_model-cache:/mnt ubuntu bash`
- `cd mnt`
- `ls`
- and delete unused models with `rm -r <model_name>`.
---
## Performance
### 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 transfer to 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?
The initial backup is the most intensive due to the number of jobs running. The most CPU-intensive ones are transcoding and machine learning jobs (Smart Search, Face Detection), and to a lesser extent thumbnail generation. Here are some ways to lower their CPU usage:
- 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.
- You _must_ re-run the Face Detection job for all images after this for facial recognition on new images to work properly.
- If these changes are not enough, see [below](/docs/FAQ#how-can-i-disable-machine-learning) for how you can disable machine learning.
### Can I limit the amount of 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.
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) to learn how to do this.
### How an I boost machine learning speed?
:::note
This advice improves throughput, not latency. This is to say that it will make Smart Search jobs process more quickly, but it won't make searching faster.
:::
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, so if you're not hitting those maximums with, say, 30 jobs.
Note that storage speed and latency may quickly become the limiting factor; particularly when using HDDs.
Do not exaggerate with the amount of jobs because you're probably thoroughly overloading the server.
more info [here](https://discord.com/channels/979116623879368755/994044917355663450/1174711719994605708)
:::
### Why is Immich using so much of my CPU?
When a large amount of assets are uploaded to Immich it makes sense that the CPU and RAM will be heavily used due to machine learning work and creating image thumbnails after that, the percentage of CPU usage will drop to around 3-5% usage
---
## Docker
### How can I see Immich logs?
Most 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 run Immich as a non-root user?
1. Set the `PUID`/`PGID` environment variables (in `.env`).
2. Set the corresponding `user` argument in `docker-compose` for each service.
3. Add an additional volume to `immich-microservices` that mounts internally to `/usr/src/app/.reverse-geocoding-dump`.
The non-root user/group needs read/write access to the volume mounts, including `UPLOAD_LOCATION`.
### How can I **purge** data from Immich?
Data for Immich comes in two forms:
1. **Metadata** stored in a postgres database, persisted via the `pg_data` volume
2. **Files** (originals, thumbs, profile, etc.), stored in the `UPLOAD_LOCATION` folder, more [info](/docs/administration/backup-and-restore#asset-types-and-storage-locations).
To remove the **Metadata** you can stop Immich and delete the volume.
```bash title="Remove Immich (containers and volumes)"
docker compose down -v
```
:::note Portainer
If you use portainer, bring down the stack in portainer. Go into the volumes section
and remove all the volumes related to immcih then restart the stack.
:::
After removing the containers and volumes, the **Files** can be cleaned up (if necessary) from the `UPLOAD_LOCATION` by simply deleting any unwanted files or folders.
### Why does the machine learning service report workers crashing?
:::note
If the error says the worker is exiting, then this is normal. This is a feature intended to reduce RAM consumption when the service isn't being used.
:::
There are a few reasons why this can happen.
If the error mentions SIGKILL or error code 137, it most likely means the service is running out of memory. Consider either increasing the server's RAM or moving the service to a server with more RAM.
If it mentions SIGILL (note the lack of a K) or error code 132, it most likely means your server's CPU is incompatible. This is unlikely to occur on version 1.92.0 or later. Consider upgrading if your version of Immich is below that.
If your version of Immich is below 1.92.0 and the crash occurs after logs about tracing or exporting a model, consider either upgrading or disabling the Tag Objects job.
### Why do I get the error "duplicate key value violates unique constraint" in the log files?
Because of Immich's container structure, this error can be seen when both immich and immich-microservices start at the same time and attempt to migrate or create the database structure. Since the database migration is run sequentially and inside of transactions, this error message does not cause harm to your installation of Immich and can safely be ignored. If needed, you can manually restart Immich by running `docker restart immich immich-microservices`.
A [3-2-1 backup strategy](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/) is recommended to protect your data. You should keep copies of your uploaded photos/videos as well as the Immich database for a comprehensive backup solution. This page provides an overview on how to backup the database and the location of user-uploaded pictures and videos. A template bash script that can be run as a cron job is provided [here](/docs/guides/template-backup-script.md)
## Database
:::caution
@@ -12,7 +17,10 @@ Refer to the official [postgres documentation](https://www.postgresql.org/docs/c
The recommended way to backup and restore the Immich database is to use the `pg_dumpall` command.
```bash title='Backup'
<Tabs>
<TabItem value="Linux system based Backup" label="Linux system based Backup" default>
docker compose up -d # Start remainder of Immich apps
```
</TabItem>
</Tabs>
Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.).
The database dumps can also be automated (using [this image](https://github.com/prodrigestivill/docker-postgres-backup-local)) by editing the docker compose file to match the following:
Immich stores two types of content in the filesystem: (1) original, unmodified content, and (2) generated content. Only the original content needs to be backed-up, which includes the following folders:
1. `UPLOAD_LOCATION/library`
1. `UPLOAD_LOCATION/upload`
1. `UPLOAD_LOCATION/profile`
2. `UPLOAD_LOCATION/upload`
3. `UPLOAD_LOCATION/profile`
### Asset Types and Storage Locations
Some storage locations are impacted by the Storage Template. See below for more details.
<Tabs>
<TabItem value="Storage Template Off (Default)." label="Storage Template Off (Default)." default>
:::note
`UPLOAD_LOCATION/library` folder is not used by default on new machines running version 1.92.0. These are if the system administrator activated the storage template engine, for [more info](https://github.com/immich-app/immich/releases#:~:text=the%20partner%E2%80%99s%20assets.-,Hardening%20storage%20template,-We%20have%20further).
:::
**1. User-Specific Folders:**
- Each user has a unique string representing them.
- You can find your user ID in Account Account Settings -> Account -> User ID.
**2. Asset Types and Storage Locations:**
- **Source Assets:**
- Original assets uploaded through the browser interface & mobile & CLI.
- Stored in `/library/upload/<userID>`.
- **Avatar Images:**
- User profile images.
- Stored in `/library/profile/<userID>`.
- **Thumbs Images:**
- Preview images (blurred, small, large) for each asset and thumbnails for recognized faces.
- Stored in `/library/thumbs/<userID>`.
- **Encoded Assets:**
- By default, unless otherwise specified re-encoded video assets for wider compatibility.
If you choose to activate the storage template engine, it will move all assets to `UPLOAD_LOCATION/library/<userID>`.
When you turn off the storage template engine, it will leave the assets in `UPLOAD_LOCATION/library/<userID>` and will not return them to `/library/upload`.
**New assets** will be saved to `/library/upload`.
:::
**1. User-Specific Folders:**
- Each user has a unique string representing them.
- The main user is "Admin" (but only for `UPLOAD_LOCATION/library`)
- Other users have different string identifiers.
- You can find your user ID in Account Account Settings -> Account -> User ID.
**2. Asset Types and Storage Locations:**
- **Source Assets:**
- Original assets uploaded through the browser interface & mobile & CLI.
- Stored in `UPLOAD_LOCATION/library/<userID>`.
- **Avatar Images:**
- User profile images.
- Stored in `/library/profile/<userID>`.
- **Thumbs Images:**
- Preview images (blurred, small, large) for each asset and thumbnails for recognized faces.
- Stored in `/library/thumbs/<userID>`.
- **Encoded Assets:**
- By default, unless otherwise specified re-encoded video assets for wider compatibility .
- Stored in `/library/encoded-video/<userID>`.
- **Files in Upload Queue (Mobile):**
- Files uploaded through mobile apps.
- Temporarily located in `/library/upload/<userID>`.
- Transferred to `UPLOAD_LOCATION/library/<userID>` upon successful upload.
</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.
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.
@@ -107,4 +107,4 @@ See [Database Migrations](./database-migrations.md) for more information about h
### Redis
Immich uses [Redis](https://redis.com/) via [BullMQ](https://docs.bullmq.io/) to manage job queues. Some jobs trigger subsequent jobs. For example, object detection relies on thumbnail generation and automatically run after one is generated.
Immich uses [Redis](https://redis.com/) via [BullMQ](https://docs.bullmq.io/) to manage job queues. Some jobs trigger subsequent jobs. For example, Smart Search and Facial Recognition relies on thumbnail generation and automatically run after one is generated.
After making any changes in the `server/src/infra/database/entities`, a database migration need to run in order to register the changes in the database. Follow the steps below to create a new migration.
After making any changes in the `server/src/infra/entities`, a database migration need to run in order to register the changes in the database. Follow the steps below to create a new migration.
@@ -7,11 +7,7 @@ Immich uses the [OpenAPI](https://swagger.io/specification/) standard to generat
OpenAPI is used to generate the client (Typescript, Dart) SDK. `openapi-generator-cli` can be installed [here](https://openapi-generator.tech/docs/installation/). The generated SDK is based on the `immich-openapi-specs.json` file, which is autogenerated by the server **when running in development mode**. The `immich-openapi-specs.json` file can be modified with `@nestjs/swagger` decorators used or referenced by controller endpoints. See the [NestJS OpenAPI docs](https://docs.nestjs.com/openapi/types-and-parameters) for more info. When you add a new endpoint or modify an existing one, you must run the server in development mode and run the command below to update the client SDK.
```bash
npm run api:generate # Run from the `server/` directory
make open-api
```
You can find the generated client SDK in the `web/src/api` for Typescript SDK and `mobile/openapi` for Dart SDK.
:::tip
This can also be run via `make api` from the project root directory (not in the `server` folder)
:::
You can find the generated client SDK in the `open-api/typescript-sdk/client` for Typescript SDK and `mobile/openapi` for Dart SDK.
If there's a feature you're planning to work on, just give us a heads up in [Discord](https://discord.com/channels/979116623879368755/1071165397228855327) so we can:
1. Let you know if it's something we would accept into Immich
2. Provide any guidance on how something like that would ideally be implemented
3. Ensure nobody is already working on that issue/feature so we don't duplicate effort
Thanks for being interested in contributing 😊
:::
## Environment
### Server and web app
@@ -16,7 +26,6 @@ This environment includes the following services:
- Web app - `/web`
- Redis
- PostgreSQL development database with exposed port `5432` so you can use any database client to acess it
- NGINX Proxy - `nginx/nginx.conf`
All the services are packaged to run as with single Docker Compose command.
@@ -37,9 +46,11 @@ All the services will be started with hot-reloading enabled for a quick feedback
You can access the web from `http://your-machine-ip:2283` or `http://localhost:2283` and access the server from the mobile app at `http://your-machine-ip:2283/api`
**Note:** the "web" development container runs with uid 1000. If that uid does not have read/write permissions on the mounted volumes, you may encounter errors
### Mobile app
The mobile app `(/mobile)` will required Flutter toolchain to be installed on your system.
The mobile app `(/mobile)` will required Flutter toolchain 3.13.x to be installed on your system.
Please refer to the [Flutter's official documentation](https://flutter.dev/docs/get-started/install) for more information on setting up the toolchain on your machine.
@@ -8,10 +8,15 @@ Unit are run by calling `npm run test` from the `server` directory.
### End to end tests
The backend has an end-to-end test suite that can be called with `npm run test:e2e` from the `server` directory. This will set up a dummy database inside a temporary container and run the tests against it. Setup and teardown is automatically taken care of. That test, however, can not set up all prerequisites to parse file formats, as that is very complex and error-prone. As such, this test excludes some test cases like HEIC file imports. The test suite will also print a friendly warning to remind you that not all tests are being run.
The backend has two end-to-end test suites that can be called with the following two commands from the project root directory:
Note that there is a bug in nodejs <20.8 that causes segmentation faults when running these tests. If you run into segfaults, ensure you are using at least version 20.8.
-`make server-e2e-api`
-`make server-e2e-jobs`
To perform a full e2e test, you need to run e2e tests inside docker. The easiest way to do that is to run `make test-e2e` in the root directory. This will build and start a docker-compose consisting of the server, microservices, and a postgres database. It will then perform the tests and exit.
#### API (e2e)
If you manually install the dependencies (see the DOCKERFILE) on your development machine, you can also run the full e2e tests manually by setting the `IMMICH_RUN_ALL_TESTS` environment value to true, i.e. `IMMICH_RUN_ALL_TESTS=true npm run test:e2e`.
The API e2e tests spin up a test database and execute http requests against the server, validating the expected response codes and functionality for API endpoints.
#### Jobs (e2e)
The Jobs e2e tests spin up a docker test environment where thumbnail generation, library scanning, and other _job_ workflows are validated.
@@ -43,12 +43,28 @@ As this is a new feature, it is still experimental and may not work on all syste
## Setup
#### Initial Setup
1. If you do not already have it, download the latest [`hwaccel.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`.
2. Uncomment the lines that apply to your system and desired usage.
3. In the `docker-compose.yml` under `immich-microservices`, uncomment the lines relating to the `hwaccel.yml` file.
4. Redeploy the `immich-microservices` container with these updated settings.
5. In the Admin page under `FFmpeg settings`, change the hardware acceleration setting to the appropriate option and save.
#### All-In-One - Unraid Setup
##### NVENC - NVIDIA GPUs
- If you are using other backends. You will still need to implement [`hwaccel.yml`][hw-file] file into the `immich-microservices` service directly, please see the "Initial Setup" section above on how to do that.
- As of v1.92.0, steps 1 and 2 are no longer necessary. If your version of Immich is below that or missing the environment variables, please follow these steps. Otherwise, skip to step 3.
- Please note that`NVIDIA_DRIVER_CAPABILITIES` is no longer required to enter as a variable.
1. Assuming you already have the Nvidia Driver Plugin installed on your Unraid Server. Please confirm that your Nvida GPU is showing up with its GPU ID in the Nvidia Driver Plugin. The ID will be `GPU-LONG_STRING_OF_CHARACTERS`. Copy the GPU ID.
2. In the Imagegenius/Immich Docker Container app, add two new variables: Key=`NVIDIA_VISIBLE_DEVICES` Value=`GPU-LONG_STRING_OF_CHARACTERS` and Key=`NVIDIA_DRIVER_CAPABILITIES` Value=`all`
3. While you are in the docker container app, change the Container from Basic Mode to Advanced Mode and add the following parameter to the Extra Parameters field: `--runtime=nvidia`
4. Restart the Imagegenius/Immich Docker Container app.
5. In the Admin page under FFmpeg settings, change the hardware acceleration setting to the appropriate option and save.
## Tips
- You may want to choose a slower preset than for software transcoding to maintain quality and efficiency
@@ -34,9 +34,11 @@ If you add assets from an external library to an album and then move the asset t
### Deleted External Assets
Note: Either a manual or scheduled library scan must have been performed to identify offline assets before this process will work.
In all above scan methods, Immich will check if any files are missing. This can happen if files are deleted, or if they are on a storage location that is currently unavailable, like a network drive that is not mounted, or a USB drive that has been unplugged. In order to prevent accidental deletion of assets, Immich will not immediately delete an asset from the library if the file is missing. Instead, the asset will be internally marked as offline and will still be visible in the main timeline. If the file is moved back to its original location and the library is scanned again, the asset will be restored.
Finally, files can be deleted from Immich via the `Remove Offline Files` job. Any assets marked as offline will then be removed from Immich. Run this job whenever files have been deleted from the file system and you want to remove them from Immich. Note that a library scan must be performed first to mark the assets as offline.
Finally, files can be deleted from Immich via the `Remove Offline Files` job. This job can be found by the three dots menu for the associated external storage that was configured under user account settings > libraries (the same location described at [create external libraries](#create-external-libraries)). When this job is run, any assets marked as offline will then be removed from Immich. Run this job whenever files have been deleted from the file system and you want to remove them from Immich.
### Import Paths
@@ -50,7 +52,11 @@ Sometimes, an external library will not scan correctly. This can happen if the i
- In the docker-compose file, are the volumes mounted correctly?
- Are the volumes identical between the `server` and `microservices` container?
- Are the import paths set correctly, and do they match the path set in docker-compose file?
- Are you using symbolic link in your import library?
- Are the permissions set correctly?
- Are you using forward slashes everywhere? (`/`)
- Are you using symlink across docker mounts?
- Are you using [spaces in the internal path](/docs/features/libraries#:~:text=can%20be%20accessed.-,NOTE,-Spaces%20in%20the)?
If all else fails, you can always start a shell inside the container and check if the path is accessible. For example, `docker exec -it immich_microservices /bin/bash` will start a bash shell. If your import path, for instance, is `/data/import/photos`, you can check if the files are accessible by running `ls /data/import/photos`. Also check the `immich_server` container in the same way.
@@ -66,16 +72,25 @@ For security purposes, each Immich user is disallowed to add external files by d
With the `external path` set, a user is restricted to accessing external files to files or directories within that path. The Immich admin should still be careful not set the external path too generously. For example, `user1` wants to read their photos in to `/home/user1`. A lazy admin sets that user's external path to `/home/` since it "gets the job done". However, that user will then be able to read all photos in `/home/user2/private-photos`, too! Please set the external path as specific as possible. If multiple folders must be added, do this using the docker volume mount feature described below.
### Exclusion Patterns and Scan Settings
### Exclusion Patterns
By default, all files in the import paths will be added to the library. If there are files that should not be added, exclusion patterns can be used to exclude them. Exclusion patterns are glob patterns are matched against the full file path. If a file matches an exclusion pattern, it will not be added to the library. Exclusion patterns can be added in the Scan Settings page for each library. Under the hood, Immich uses the [glob](https://www.npmjs.com/package/glob) package to match patterns, so please refer to [their documentation](https://github.com/isaacs/node-glob#glob-primer) to see what patterns are supported.
Some basic examples:
-`*.tif` will exclude all files with the extension `.tif`
-`hidden.jpg` will exclude all files named `hidden.jpg`
-`**/*.tif` will exclude all files with the extension `.tif`
-`**/hidden.jpg` will exclude all files named `hidden.jpg`
-`**/Raw/**` will exclude all files in any directory named `Raw`
-`*.{tif,jpg}` will exclude all files with the extension `.tif` or `.jpg`
-`**/*.{tif,jpg}` will exclude all files with the extension `.tif` or `.jpg`
### Automatic watching (EXPERIMENTAL)
This feature - currently hidden in the config file - is considered experimental and for advanced users only. If enabled, it will allow automatic watching of the filesystem which means new assets are automatically imported to Immich without needing to rescan. Deleted assets are, as always, marked as offline and can be removed with the "Remove offline files" button.
If your photos are on a network drive you will likely have to enable filesystem polling. The performance hit for polling large libraries is currently unknown, feel free to test this feature and report back. In addition to the boolean feature flag, the configuration file allows customization of the following parameters, please see the [chokidar documentation](https://github.com/paulmillr/chokidar?tab=readme-ov-file#performance) for reference.
-`usePolling` (default: `false`).
-`interval`. (default: 10000). When using polling, this is how often (in milliseconds) the filesystem is polled.
### Nightly job
@@ -102,6 +117,7 @@ First, we need to plan how we want to organize the libraries. The christmas trip
This page gives a few pointers on how to access your Immich instance from outside your LAN.
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.
@@ -41,7 +42,7 @@ If you are unable to open a port on your router for Wireguard or OpenVPN to your
A reverse proxy is a service that sits between web servers and clients. A reverse proxy can either be hosted on the server itself or remotely. Clients can connect to the reverse proxy via https, and the proxy relays data to Immich. This setup makes most sense if you have your own domain and want to access your Immich instance just like any other website, from outside your LAN. You can also use a DDNS provider like DuckDNS or no-ip if you don't have a domain. This configuration allows the Immich Android and iphone apps to connect to your server without a VPN or tailscale app on the client side.
If you're hosting your own reverse proxy, [Nginx](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) is a great option. An example configuration for Nginx is provided [here](https://immich.app/docs/administration/reverse-proxy).
If you're hosting your own reverse proxy, [Nginx](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) is a great option. An example configuration for Nginx is provided [here](/docs/administration/reverse-proxy.md).
You'll also need your own certificate to authenticate https connections. If you're making Immich publicly accesible, [Let's Encrypt](https://letsencrypt.org/) can provide a free certificate for your domain and is the recommended option. Alternatively, a [self-signed certificate](https://en.wikipedia.org/wiki/Self-signed_certificate) allows you to encrypt your connection to Immich, but it raises a security warning on the client's browser.
To alleviate [performance issues on low-memory systems](/docs/FAQ.md#why-is-immich-slow-on-low-memory-systems-like-the-raspberry-pi) like the Raspberry Pi, you may also host Immich's machine-learning container on a more powerful system (e.g. your laptop or desktop computer):
To alleviate [performance issues on low-memory systems](/docs/FAQ.mdx#why-is-immich-slow-on-low-memory-systems-like-the-raspberry-pi) like the Raspberry Pi, you may also host Immich's machine-learning container on a more powerful system (e.g. your laptop or desktop computer):
- 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.
- Start the container by running `docker-compose up -d` or `docker compose up -d` (depending on your Docker version).
:::note 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 service, but facial recognition is done in the immich_microservices service.
:::
```yaml
version: '3.8'
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.