Compare commits

...

22 Commits

Author SHA1 Message Date
Alex The Bot 08f66c2ae5 Version v1.91.3 2023-12-17 16:57:16 +00:00
Mert 4f38a283b4 fix(server): stricter dim size check for pgvecto.rs migration (#5767)
* stricter dim size check

* remove unused import

* added null check
2023-12-17 10:55:35 -06:00
Jon Howell 00771899da fix(docs): remove inline dev inquiries (#5733)
* fix(docs): correct link; remove inline dev inquiries

* unfix relative path
2023-12-17 10:46:29 -05:00
Mert 09402eb6d0 fix(ml): disable core dumps (#5770)
* update dockerfile

* remove sysctl line
2023-12-16 20:30:29 -06:00
Jon Howell d9b5adf0f7 fix(docs): remove spurious hyphen in docker compose cmd (#5771)
The command example is correct, but the text just before it still references the old docker-compose command.
2023-12-16 19:49:14 -05:00
Alex The Bot a15c799ba3 Version v1.91.2 2023-12-16 23:19:58 +00:00
Daniel Dietzler bda9fd9dfe fix(web): settings switch state when disabled, simplify classes (#5762) 2023-12-16 17:17:38 -06:00
Daniel Dietzler 19754d4b21 fix clip concurrency not being persisted after queue renaming (#5769) 2023-12-16 22:32:15 +00:00
Alex 62347edf43 chore(web): improve map pin (#5761)
* chore(web): improve map pin

* zoom level
2023-12-16 20:21:13 +00:00
Daniel Dietzler 67f020380f disable version check settings when config file is set (#5756) 2023-12-16 20:39:17 +01:00
Alex The Bot 0aae9696f6 Version v1.91.1 2023-12-16 17:26:51 +00:00
martin 2f95cb89c1 fix(web): use env for web folder path (#5753)
* fix: use env for web folder path

* feat: use constant

* fix: use join

* update docs

* fix: icon
2023-12-16 11:15:30 -06:00
Mert cb1201e690 chore(web): update job dashboard (#5745)
* rename clip encoding to smart search

* update job subtitles

* update api

* update smart search job title and subtitle

* fix `getJobName`

* change smart search icon

* formatting

* wording

* update reference to clip

* formatting

* update reference to Encode CLIP
2023-12-16 10:50:46 -06:00
Daniel Dietzler a2deba4734 fix(web): never ungroup map markers. ever. (#5730) 2023-12-16 10:49:58 -06:00
Alex ae2608e31d fix(web): cannot save exclusion pattern (#5738)
* fix(web): Ccannot save exclusive pattern

* remove console log
2023-12-16 10:48:49 -06:00
Mert d8756f3897 fix(web): searching places (#5746) 2023-12-16 10:48:27 -06:00
Mohamed BOUSSAID 7839be3b49 Adding the new models to the whitelist (#5736) 2023-12-15 22:45:14 +00:00
Jason Rasmussen 94e11d52dc docs: fix redirects for cloudflare (#5734) 2023-12-15 15:20:50 -06:00
Jon Howell 05a1283500 fix(docs): Add title for External Library guide (#5732) 2023-12-15 14:38:14 -05:00
Alex f8519d60c7 chore: post release tasks 2023-12-15 13:25:37 -06:00
Jon Howell 899c71f297 docs: add a walk-through guide for External Libraries (#5594)
* Add a walk-through guide for External Libraries

* Apply prettier to markdown

* Add screenshots for GUI elements

* fix format
2023-12-15 12:46:43 -06:00
martin 2aa5f55cbf docs: update milestone page (#5663) 2023-12-15 09:50:13 -06:00
81 changed files with 330 additions and 210 deletions
+14 -14
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@@ -355,12 +355,6 @@ export interface AllJobStatusResponseDto {
* @memberof AllJobStatusResponseDto
*/
'backgroundTask': JobStatusDto;
/**
*
* @type {JobStatusDto}
* @memberof AllJobStatusResponseDto
*/
'clipEncoding': JobStatusDto;
/**
*
* @type {JobStatusDto}
@@ -403,6 +397,12 @@ export interface AllJobStatusResponseDto {
* @memberof AllJobStatusResponseDto
*/
'sidecar': JobStatusDto;
/**
*
* @type {JobStatusDto}
* @memberof AllJobStatusResponseDto
*/
'smartSearch': JobStatusDto;
/**
*
* @type {JobStatusDto}
@@ -2017,7 +2017,7 @@ export const JobName = {
VideoConversion: 'videoConversion',
ObjectTagging: 'objectTagging',
RecognizeFaces: 'recognizeFaces',
ClipEncoding: 'clipEncoding',
SmartSearch: 'smartSearch',
BackgroundTask: 'backgroundTask',
StorageTemplateMigration: 'storageTemplateMigration',
Migration: 'migration',
@@ -3785,12 +3785,6 @@ export interface SystemConfigJobDto {
* @memberof SystemConfigJobDto
*/
'backgroundTask': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
* @memberof SystemConfigJobDto
*/
'clipEncoding': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
@@ -3833,6 +3827,12 @@ export interface SystemConfigJobDto {
* @memberof SystemConfigJobDto
*/
'sidecar': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
* @memberof SystemConfigJobDto
*/
'smartSearch': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
+1 -1
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+1 -1
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+1 -1
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+1 -1
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+1 -1
View File
@@ -26,7 +26,7 @@ Immich optionally uses machine learning for several features. However, it can be
### 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, Encode CLIP, Recognize Faces), and to a lesser extent thumbnail generation. Here are some ways to lower their 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.
+100
View File
@@ -0,0 +1,100 @@
# External Library
This guide walks you through adding an [External Library](../features/libraries#external-libraries).
This guide assumes you are running Immich in Docker and that the files you wish to access are stored
in a directory on the same machine.
# Mount the directory into the containers.
Edit `docker-compose.yml` to add two new mount points under `volumes:`
```
immich-server:
volumes:
- ${EXTERNAL_PATH}:/usr/src/app/external
```
Be sure to add exactly the same line to both `immich-server:` and `immich-microservices:`.
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
```
Restart Immich.
```
docker compose down
docker compose up -d
```
# Set the External Path
In the Immich web UI:
- click the **Administration** link in the upper right corner.
<img src={require('./img/administration-link.png').default} width="50%" title="Administration link" />
- Select the **Users** tab
<img src={require('./img/users-tab.png').default} width="50%" title="Users tab" />
- Select the **pencil** next to your user ID
<img src={require('./img/pencil.png').default} width="50%" title="Pencil" />
- Fill in the **External Path** field with `/usr/src/app/external`
<img src={require('./img/external-path.png').default} width="50%" title="External Path field" />
Notice this matches the path _inside the container_ where we mounted your photos.
The purpose of the external path field is for administrators who have multiple users
on their Immich instance. It lets you prevent other authorized users from
navigating to your external library.
# Import the library
In the Immich web UI:
- Click your user avatar in the upper-right corner (circle with your initials)
<img src={require('./img/user-avatar.png').default} width="50%" title="User avatar" />
- Click **Account Settings**
<img src={require('./img/account-settings.png').default} width="50%" title="Account Settings button" />
- Click to expand **Libraries**
<img src={require('./img/libraries-dropdown.png').default} width="50%" title="Libraries dropdown" />
- Click the **Create External Library** button
<img src={require('./img/create-external-library-button.png').default} width="50%" title="Create External Library button" />
- Click the three-dots menu and select **Edit Import Paths**
<img src={require('./img/edit-import-paths.png').default} width="50%" title="Edit Import Paths menu option" />
- Click \*_Add path_
<img src={require('./img/add-path-button.png').default} width="50%" title="Add Path button" />
- Enter **.** as the path and click Add
<img src={require('./img/add-path-field.png').default} width="50%" title="Add Path field" />
- Save the new path
<img src={require('./img/path-save.png').default} width="50%" title="Path Save button" />
- Click the three-dots menu and select **Scan New Library Files**
<img src={require('./img/scan-new-library-files.png').default} width="50%" title="Scan New Library Files menu option" />
# Confirm stuff is happening
- Click **Administration**
<img src={require('./img/administration-link.png').default} width="50%" title="Administration link" />
- Select the **Jobs** tab
<img src={require('./img/jobs-tab.png').default} width="50%" title="Jobs tab" />
- You should see non-zero Active jobs for
Library, Generate Thumbnails, and Extract Metadata.
<img src={require('./img/job-status.png').default} width="50%" title="Job Status display" />
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+1 -1
View File
@@ -55,7 +55,7 @@ Optionally, you can use the [`hwaccel.yml`][hw-file] file to enable hardware acc
### Step 3 - Start the containers
From the directory you created in Step 1, (which should now contain your customized `docker-compose.yml` and `.env` files) run `docker-compose up -d`.
From the directory you created in Step 1, (which should now contain your customized `docker-compose.yml` and `.env` files) run `docker compose up -d`.
```bash title="Start the containers using docker compose command"
docker compose up -d
+9 -8
View File
@@ -30,14 +30,15 @@ These environment variables are used by the `docker-compose.yml` file and do **N
## General
| Variable | Description | Default | Services |
| :-------------------------- | :------------------------------------------- | :----------: | :------------------------------------------- |
| `TZ` | Timezone | | microservices |
| `NODE_ENV` | Environment (production, development) | `production` | server, microservices, machine learning, web |
| `LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, microservices |
| `IMMICH_MEDIA_LOCATION` | Media Location | `./upload` | server, microservices |
| `PUBLIC_LOGIN_PAGE_MESSAGE` | Public Login Page Message | | web |
| `IMMICH_CONFIG_FILE` | Path to config file | | server |
| Variable | Description | Default | Services |
| :-------------------------- | :------------------------------------------- | :-----------------: | :------------------------------------------- |
| `TZ` | Timezone | | microservices |
| `NODE_ENV` | Environment (production, development) | `production` | server, microservices, machine learning, web |
| `LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, microservices |
| `IMMICH_MEDIA_LOCATION` | Media Location | `./upload` | server, microservices |
| `PUBLIC_LOGIN_PAGE_MESSAGE` | Public Login Page Message | | web |
| `IMMICH_CONFIG_FILE` | Path to config file | | server |
| `IMMICH_WEB_ROOT` | Path of root index.html | `/usr/src/app/www'` | server |
:::tip
+20
View File
@@ -26,12 +26,14 @@ import {
mdiMagnify,
mdiMap,
mdiMaterialDesign,
mdiMatrix,
mdiMerge,
mdiMonitor,
mdiMotionPlayOutline,
mdiPalette,
mdiPanVertical,
mdiPartyPopper,
mdiPencil,
mdiRaw,
mdiRotate360,
mdiSecurity,
@@ -52,6 +54,24 @@ import React from 'react';
import Timeline, { DateType, Item } from '../components/timeline';
const items: Item[] = [
{
icon: mdiMatrix,
description: 'Moved the search from typesense to pgvecto.rs',
title: 'Search improvement with pgvecto.rs',
release: 'v1.91.0',
tag: 'v1.91.0',
date: new Date(2023, 11, 15),
dateType: DateType.RELEASE,
},
{
icon: mdiPencil,
description: "Edit a photo or video's date, time, hours, timezone, and GPS information",
title: 'Edit metadata',
release: 'v1.90.0',
tag: 'v1.90.0',
date: new Date(2023, 11, 7),
dateType: DateType.RELEASE,
},
{
icon: mdiVectorCombine,
description:
-1
View File
@@ -23,4 +23,3 @@
/docs/features/storage-template /docs/administration/storage-template 301
/docs/features/user-management /docs/administration/user-management 301
/docs/developer/contributing /docs/developer/pr-checklist 301
-29
View File
@@ -1,29 +0,0 @@
{
"redirects": [
{ "source": "/docs", "destination": "/docs/overview/introduction" },
{ "source": "/docs/mobile-app-beta-program", "destination": "/docs/features/mobile-app" },
{ "source": "/docs/contribution-guidelines", "destination": "/docs/overview/support-the-project#contributing" },
{ "source": "/docs/install", "destination": "/docs/install/docker-compose" },
{ "source": "/docs/installation/one-step-installation", "destination": "/docs/install/script" },
{ "source": "/docs/installation/portainer-installation", "destination": "/docs/install/portainer" },
{ "source": "/docs/installation/recommended-installation", "destination": "/docs/install/docker-compose" },
{ "source": "/docs/installation/unraid", "destination": "/docs/install/unraid" },
{ "source": "/docs/installation/requirements", "destination": "/docs/install/requirements" },
{ "source": "/docs/overview/logo-meaning", "destination": "/docs/overview/logo" },
{ "source": "/docs/overview/technology-stack", "destination": "/docs/developer/architecture" },
{ "source": "/docs/usage/automatic-backup", "destination": "/docs/features/automatic-backup" },
{ "source": "/docs/usage/bulk-upload", "destination": "/docs/features/command-line-interface" },
{ "source": "/docs/features/bulk-upload", "destination": "/docs/features/command-line-interface" },
{ "source": "/docs/usage/oauth", "destination": "/docs/administration/oauth" },
{ "source": "/docs/usage/post-installation", "destination": "/docs/install/post-install" },
{ "source": "/docs/usage/update", "destination": "/docs/install/docker-compose#step-4---upgrading" },
{ "source": "/docs/usage/server-commands", "destination": "/docs/administration/server-commands" },
{ "source": "/docs/features/jobs", "destination": "/docs/administration/jobs" },
{ "source": "/docs/features/oauth", "destination": "/docs/administration/oauth" },
{ "source": "/docs/features/password-login", "destination": "/docs/administration/password-login" },
{ "source": "/docs/features/server-commands", "destination": "/docs/administration/server-commands" },
{ "source": "/docs/features/storage-template", "destination": "/docs/administration/storage-template" },
{ "source": "/docs/features/user-management", "destination": "/docs/administration/user-management" },
{ "source": "/docs/developer/contributing", "destination": "/docs/developer/pr-checklist" }
]
}
+5
View File
@@ -25,6 +25,11 @@ ENV NODE_ENV=production \
PATH="/opt/venv/bin:$PATH" \
PYTHONPATH=/usr/src
# prevent core dumps
RUN echo "hard core 0" >> /etc/security/limits.conf && \
echo "fs.suid_dumpable 0" >> /etc/sysctl.conf && \
echo 'ulimit -S -c 0 > /dev/null 2>&1' >> /etc/profile
COPY --from=builder /opt/venv /opt/venv
COPY start.sh log_conf.json ./
COPY app .
+6
View File
@@ -26,6 +26,9 @@ _OPENCLIP_MODELS = {
"ViT-L-14-336__openai",
"ViT-H-14__laion2b-s32b-b79k",
"ViT-g-14__laion2b-s12b-b42k",
"ViT-L-14-quickgelu__dfn2b",
"ViT-H-14-quickgelu__dfn5b",
"ViT-H-14-378-quickgelu__dfn5b",
}
@@ -34,6 +37,9 @@ _MCLIP_MODELS = {
"XLM-Roberta-Large-Vit-B-32",
"XLM-Roberta-Large-Vit-B-16Plus",
"XLM-Roberta-Large-Vit-L-14",
"XLM-Roberta-Large-ViT-H-14__frozen_laion5b_s13b_b90k",
"nllb-clip-base-siglip__v1",
"nllb-clip-large-siglip__v1",
}
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "machine-learning"
version = "1.91.0"
version = "1.91.3"
description = ""
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
readme = "README.md"
+1 -1
View File
@@ -36,7 +36,7 @@ platform :android do
build_type: 'Release',
properties: {
"android.injected.version.code" => 115,
"android.injected.version.name" => "1.91.0",
"android.injected.version.name" => "1.91.3",
}
)
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
+3 -3
View File
@@ -5,17 +5,17 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000235">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000217">
</testcase>
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="27.74518">
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="66.694734">
</testcase>
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="25.612783">
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="27.6926">
</testcase>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 KiB

+1 -1
View File
@@ -169,4 +169,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
COCOAPODS: 1.11.3
COCOAPODS: 1.12.1
+3 -3
View File
@@ -379,7 +379,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 130;
CURRENT_PROJECT_VERSION = 131;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -515,7 +515,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 130;
CURRENT_PROJECT_VERSION = 131;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -543,7 +543,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 130;
CURRENT_PROJECT_VERSION = 131;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+2 -2
View File
@@ -54,11 +54,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.90.0</string>
<string>1.91.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>130</string>
<string>131</string>
<key>FLTEnableImpeller</key>
<true />
<key>ITSAppUsesNonExemptEncryption</key>
+1 -1
View File
@@ -19,7 +19,7 @@ platform :ios do
desc "iOS Beta"
lane :beta do
increment_version_number(
version_number: "1.91.0"
version_number: "1.91.3"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,
+6 -6
View File
@@ -5,32 +5,32 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000234">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000273">
</testcase>
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.207521">
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.162117">
</testcase>
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="18.516191">
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="3.645923">
</testcase>
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.23018">
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.158953">
</testcase>
<testcase classname="fastlane.lanes" name="4: build_app" time="104.984834">
<testcase classname="fastlane.lanes" name="4: build_app" time="114.023733">
</testcase>
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="61.879749">
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="97.572612">
</testcase>
+1 -1
View File
@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 1.91.0
- API version: 1.91.3
- Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements
+1 -1
View File
@@ -9,7 +9,6 @@ import 'package:openapi/api.dart';
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**backgroundTask** | [**JobStatusDto**](JobStatusDto.md) | |
**clipEncoding** | [**JobStatusDto**](JobStatusDto.md) | |
**library_** | [**JobStatusDto**](JobStatusDto.md) | |
**metadataExtraction** | [**JobStatusDto**](JobStatusDto.md) | |
**migration** | [**JobStatusDto**](JobStatusDto.md) | |
@@ -17,6 +16,7 @@ Name | Type | Description | Notes
**recognizeFaces** | [**JobStatusDto**](JobStatusDto.md) | |
**search** | [**JobStatusDto**](JobStatusDto.md) | |
**sidecar** | [**JobStatusDto**](JobStatusDto.md) | |
**smartSearch** | [**JobStatusDto**](JobStatusDto.md) | |
**storageTemplateMigration** | [**JobStatusDto**](JobStatusDto.md) | |
**thumbnailGeneration** | [**JobStatusDto**](JobStatusDto.md) | |
**videoConversion** | [**JobStatusDto**](JobStatusDto.md) | |
+1 -1
View File
@@ -9,7 +9,6 @@ import 'package:openapi/api.dart';
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**backgroundTask** | [**JobSettingsDto**](JobSettingsDto.md) | |
**clipEncoding** | [**JobSettingsDto**](JobSettingsDto.md) | |
**library_** | [**JobSettingsDto**](JobSettingsDto.md) | |
**metadataExtraction** | [**JobSettingsDto**](JobSettingsDto.md) | |
**migration** | [**JobSettingsDto**](JobSettingsDto.md) | |
@@ -17,6 +16,7 @@ Name | Type | Description | Notes
**recognizeFaces** | [**JobSettingsDto**](JobSettingsDto.md) | |
**search** | [**JobSettingsDto**](JobSettingsDto.md) | |
**sidecar** | [**JobSettingsDto**](JobSettingsDto.md) | |
**smartSearch** | [**JobSettingsDto**](JobSettingsDto.md) | |
**storageTemplateMigration** | [**JobSettingsDto**](JobSettingsDto.md) | |
**thumbnailGeneration** | [**JobSettingsDto**](JobSettingsDto.md) | |
**videoConversion** | [**JobSettingsDto**](JobSettingsDto.md) | |
+9 -9
View File
@@ -14,7 +14,6 @@ class AllJobStatusResponseDto {
/// Returns a new [AllJobStatusResponseDto] instance.
AllJobStatusResponseDto({
required this.backgroundTask,
required this.clipEncoding,
required this.library_,
required this.metadataExtraction,
required this.migration,
@@ -22,6 +21,7 @@ class AllJobStatusResponseDto {
required this.recognizeFaces,
required this.search,
required this.sidecar,
required this.smartSearch,
required this.storageTemplateMigration,
required this.thumbnailGeneration,
required this.videoConversion,
@@ -29,8 +29,6 @@ class AllJobStatusResponseDto {
JobStatusDto backgroundTask;
JobStatusDto clipEncoding;
JobStatusDto library_;
JobStatusDto metadataExtraction;
@@ -45,6 +43,8 @@ class AllJobStatusResponseDto {
JobStatusDto sidecar;
JobStatusDto smartSearch;
JobStatusDto storageTemplateMigration;
JobStatusDto thumbnailGeneration;
@@ -54,7 +54,6 @@ class AllJobStatusResponseDto {
@override
bool operator ==(Object other) => identical(this, other) || other is AllJobStatusResponseDto &&
other.backgroundTask == backgroundTask &&
other.clipEncoding == clipEncoding &&
other.library_ == library_ &&
other.metadataExtraction == metadataExtraction &&
other.migration == migration &&
@@ -62,6 +61,7 @@ class AllJobStatusResponseDto {
other.recognizeFaces == recognizeFaces &&
other.search == search &&
other.sidecar == sidecar &&
other.smartSearch == smartSearch &&
other.storageTemplateMigration == storageTemplateMigration &&
other.thumbnailGeneration == thumbnailGeneration &&
other.videoConversion == videoConversion;
@@ -70,7 +70,6 @@ class AllJobStatusResponseDto {
int get hashCode =>
// ignore: unnecessary_parenthesis
(backgroundTask.hashCode) +
(clipEncoding.hashCode) +
(library_.hashCode) +
(metadataExtraction.hashCode) +
(migration.hashCode) +
@@ -78,17 +77,17 @@ class AllJobStatusResponseDto {
(recognizeFaces.hashCode) +
(search.hashCode) +
(sidecar.hashCode) +
(smartSearch.hashCode) +
(storageTemplateMigration.hashCode) +
(thumbnailGeneration.hashCode) +
(videoConversion.hashCode);
@override
String toString() => 'AllJobStatusResponseDto[backgroundTask=$backgroundTask, clipEncoding=$clipEncoding, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, objectTagging=$objectTagging, recognizeFaces=$recognizeFaces, search=$search, sidecar=$sidecar, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]';
String toString() => 'AllJobStatusResponseDto[backgroundTask=$backgroundTask, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, objectTagging=$objectTagging, recognizeFaces=$recognizeFaces, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'backgroundTask'] = this.backgroundTask;
json[r'clipEncoding'] = this.clipEncoding;
json[r'library'] = this.library_;
json[r'metadataExtraction'] = this.metadataExtraction;
json[r'migration'] = this.migration;
@@ -96,6 +95,7 @@ class AllJobStatusResponseDto {
json[r'recognizeFaces'] = this.recognizeFaces;
json[r'search'] = this.search;
json[r'sidecar'] = this.sidecar;
json[r'smartSearch'] = this.smartSearch;
json[r'storageTemplateMigration'] = this.storageTemplateMigration;
json[r'thumbnailGeneration'] = this.thumbnailGeneration;
json[r'videoConversion'] = this.videoConversion;
@@ -111,7 +111,6 @@ class AllJobStatusResponseDto {
return AllJobStatusResponseDto(
backgroundTask: JobStatusDto.fromJson(json[r'backgroundTask'])!,
clipEncoding: JobStatusDto.fromJson(json[r'clipEncoding'])!,
library_: JobStatusDto.fromJson(json[r'library'])!,
metadataExtraction: JobStatusDto.fromJson(json[r'metadataExtraction'])!,
migration: JobStatusDto.fromJson(json[r'migration'])!,
@@ -119,6 +118,7 @@ class AllJobStatusResponseDto {
recognizeFaces: JobStatusDto.fromJson(json[r'recognizeFaces'])!,
search: JobStatusDto.fromJson(json[r'search'])!,
sidecar: JobStatusDto.fromJson(json[r'sidecar'])!,
smartSearch: JobStatusDto.fromJson(json[r'smartSearch'])!,
storageTemplateMigration: JobStatusDto.fromJson(json[r'storageTemplateMigration'])!,
thumbnailGeneration: JobStatusDto.fromJson(json[r'thumbnailGeneration'])!,
videoConversion: JobStatusDto.fromJson(json[r'videoConversion'])!,
@@ -170,7 +170,6 @@ class AllJobStatusResponseDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'backgroundTask',
'clipEncoding',
'library',
'metadataExtraction',
'migration',
@@ -178,6 +177,7 @@ class AllJobStatusResponseDto {
'recognizeFaces',
'search',
'sidecar',
'smartSearch',
'storageTemplateMigration',
'thumbnailGeneration',
'videoConversion',
+3 -3
View File
@@ -28,7 +28,7 @@ class JobName {
static const videoConversion = JobName._(r'videoConversion');
static const objectTagging = JobName._(r'objectTagging');
static const recognizeFaces = JobName._(r'recognizeFaces');
static const clipEncoding = JobName._(r'clipEncoding');
static const smartSearch = JobName._(r'smartSearch');
static const backgroundTask = JobName._(r'backgroundTask');
static const storageTemplateMigration = JobName._(r'storageTemplateMigration');
static const migration = JobName._(r'migration');
@@ -43,7 +43,7 @@ class JobName {
videoConversion,
objectTagging,
recognizeFaces,
clipEncoding,
smartSearch,
backgroundTask,
storageTemplateMigration,
migration,
@@ -93,7 +93,7 @@ class JobNameTypeTransformer {
case r'videoConversion': return JobName.videoConversion;
case r'objectTagging': return JobName.objectTagging;
case r'recognizeFaces': return JobName.recognizeFaces;
case r'clipEncoding': return JobName.clipEncoding;
case r'smartSearch': return JobName.smartSearch;
case r'backgroundTask': return JobName.backgroundTask;
case r'storageTemplateMigration': return JobName.storageTemplateMigration;
case r'migration': return JobName.migration;
+9 -9
View File
@@ -14,7 +14,6 @@ class SystemConfigJobDto {
/// Returns a new [SystemConfigJobDto] instance.
SystemConfigJobDto({
required this.backgroundTask,
required this.clipEncoding,
required this.library_,
required this.metadataExtraction,
required this.migration,
@@ -22,6 +21,7 @@ class SystemConfigJobDto {
required this.recognizeFaces,
required this.search,
required this.sidecar,
required this.smartSearch,
required this.storageTemplateMigration,
required this.thumbnailGeneration,
required this.videoConversion,
@@ -29,8 +29,6 @@ class SystemConfigJobDto {
JobSettingsDto backgroundTask;
JobSettingsDto clipEncoding;
JobSettingsDto library_;
JobSettingsDto metadataExtraction;
@@ -45,6 +43,8 @@ class SystemConfigJobDto {
JobSettingsDto sidecar;
JobSettingsDto smartSearch;
JobSettingsDto storageTemplateMigration;
JobSettingsDto thumbnailGeneration;
@@ -54,7 +54,6 @@ class SystemConfigJobDto {
@override
bool operator ==(Object other) => identical(this, other) || other is SystemConfigJobDto &&
other.backgroundTask == backgroundTask &&
other.clipEncoding == clipEncoding &&
other.library_ == library_ &&
other.metadataExtraction == metadataExtraction &&
other.migration == migration &&
@@ -62,6 +61,7 @@ class SystemConfigJobDto {
other.recognizeFaces == recognizeFaces &&
other.search == search &&
other.sidecar == sidecar &&
other.smartSearch == smartSearch &&
other.storageTemplateMigration == storageTemplateMigration &&
other.thumbnailGeneration == thumbnailGeneration &&
other.videoConversion == videoConversion;
@@ -70,7 +70,6 @@ class SystemConfigJobDto {
int get hashCode =>
// ignore: unnecessary_parenthesis
(backgroundTask.hashCode) +
(clipEncoding.hashCode) +
(library_.hashCode) +
(metadataExtraction.hashCode) +
(migration.hashCode) +
@@ -78,17 +77,17 @@ class SystemConfigJobDto {
(recognizeFaces.hashCode) +
(search.hashCode) +
(sidecar.hashCode) +
(smartSearch.hashCode) +
(storageTemplateMigration.hashCode) +
(thumbnailGeneration.hashCode) +
(videoConversion.hashCode);
@override
String toString() => 'SystemConfigJobDto[backgroundTask=$backgroundTask, clipEncoding=$clipEncoding, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, objectTagging=$objectTagging, recognizeFaces=$recognizeFaces, search=$search, sidecar=$sidecar, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]';
String toString() => 'SystemConfigJobDto[backgroundTask=$backgroundTask, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, objectTagging=$objectTagging, recognizeFaces=$recognizeFaces, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'backgroundTask'] = this.backgroundTask;
json[r'clipEncoding'] = this.clipEncoding;
json[r'library'] = this.library_;
json[r'metadataExtraction'] = this.metadataExtraction;
json[r'migration'] = this.migration;
@@ -96,6 +95,7 @@ class SystemConfigJobDto {
json[r'recognizeFaces'] = this.recognizeFaces;
json[r'search'] = this.search;
json[r'sidecar'] = this.sidecar;
json[r'smartSearch'] = this.smartSearch;
json[r'storageTemplateMigration'] = this.storageTemplateMigration;
json[r'thumbnailGeneration'] = this.thumbnailGeneration;
json[r'videoConversion'] = this.videoConversion;
@@ -111,7 +111,6 @@ class SystemConfigJobDto {
return SystemConfigJobDto(
backgroundTask: JobSettingsDto.fromJson(json[r'backgroundTask'])!,
clipEncoding: JobSettingsDto.fromJson(json[r'clipEncoding'])!,
library_: JobSettingsDto.fromJson(json[r'library'])!,
metadataExtraction: JobSettingsDto.fromJson(json[r'metadataExtraction'])!,
migration: JobSettingsDto.fromJson(json[r'migration'])!,
@@ -119,6 +118,7 @@ class SystemConfigJobDto {
recognizeFaces: JobSettingsDto.fromJson(json[r'recognizeFaces'])!,
search: JobSettingsDto.fromJson(json[r'search'])!,
sidecar: JobSettingsDto.fromJson(json[r'sidecar'])!,
smartSearch: JobSettingsDto.fromJson(json[r'smartSearch'])!,
storageTemplateMigration: JobSettingsDto.fromJson(json[r'storageTemplateMigration'])!,
thumbnailGeneration: JobSettingsDto.fromJson(json[r'thumbnailGeneration'])!,
videoConversion: JobSettingsDto.fromJson(json[r'videoConversion'])!,
@@ -170,7 +170,6 @@ class SystemConfigJobDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'backgroundTask',
'clipEncoding',
'library',
'metadataExtraction',
'migration',
@@ -178,6 +177,7 @@ class SystemConfigJobDto {
'recognizeFaces',
'search',
'sidecar',
'smartSearch',
'storageTemplateMigration',
'thumbnailGeneration',
'videoConversion',
+5 -5
View File
@@ -21,11 +21,6 @@ void main() {
// TODO
});
// JobStatusDto clipEncoding
test('to test the property `clipEncoding`', () async {
// TODO
});
// JobStatusDto library_
test('to test the property `library_`', () async {
// TODO
@@ -61,6 +56,11 @@ void main() {
// TODO
});
// JobStatusDto smartSearch
test('to test the property `smartSearch`', () async {
// TODO
});
// JobStatusDto storageTemplateMigration
test('to test the property `storageTemplateMigration`', () async {
// TODO
+5 -5
View File
@@ -21,11 +21,6 @@ void main() {
// TODO
});
// JobSettingsDto clipEncoding
test('to test the property `clipEncoding`', () async {
// TODO
});
// JobSettingsDto library_
test('to test the property `library_`', () async {
// TODO
@@ -61,6 +56,11 @@ void main() {
// TODO
});
// JobSettingsDto smartSearch
test('to test the property `smartSearch`', () async {
// TODO
});
// JobSettingsDto storageTemplateMigration
test('to test the property `storageTemplateMigration`', () async {
// TODO
+1 -1
View File
@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: "none"
version: 1.91.0+115
version: 1.91.3+115
isar_version: &isar_version 3.1.0+1
environment:
+10 -10
View File
@@ -6188,7 +6188,7 @@
"info": {
"title": "Immich",
"description": "Immich API",
"version": "1.91.0",
"version": "1.91.3",
"contact": {}
},
"tags": [],
@@ -6470,9 +6470,6 @@
"backgroundTask": {
"$ref": "#/components/schemas/JobStatusDto"
},
"clipEncoding": {
"$ref": "#/components/schemas/JobStatusDto"
},
"library": {
"$ref": "#/components/schemas/JobStatusDto"
},
@@ -6494,6 +6491,9 @@
"sidecar": {
"$ref": "#/components/schemas/JobStatusDto"
},
"smartSearch": {
"$ref": "#/components/schemas/JobStatusDto"
},
"storageTemplateMigration": {
"$ref": "#/components/schemas/JobStatusDto"
},
@@ -6509,7 +6509,7 @@
"metadataExtraction",
"videoConversion",
"objectTagging",
"clipEncoding",
"smartSearch",
"storageTemplateMigration",
"migration",
"backgroundTask",
@@ -7821,7 +7821,7 @@
"videoConversion",
"objectTagging",
"recognizeFaces",
"clipEncoding",
"smartSearch",
"backgroundTask",
"storageTemplateMigration",
"migration",
@@ -9182,9 +9182,6 @@
"backgroundTask": {
"$ref": "#/components/schemas/JobSettingsDto"
},
"clipEncoding": {
"$ref": "#/components/schemas/JobSettingsDto"
},
"library": {
"$ref": "#/components/schemas/JobSettingsDto"
},
@@ -9206,6 +9203,9 @@
"sidecar": {
"$ref": "#/components/schemas/JobSettingsDto"
},
"smartSearch": {
"$ref": "#/components/schemas/JobSettingsDto"
},
"storageTemplateMigration": {
"$ref": "#/components/schemas/JobSettingsDto"
},
@@ -9221,7 +9221,7 @@
"metadataExtraction",
"videoConversion",
"objectTagging",
"clipEncoding",
"smartSearch",
"storageTemplateMigration",
"migration",
"backgroundTask",
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "immich",
"version": "1.91.0",
"version": "1.91.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "immich",
"version": "1.91.0",
"version": "1.91.3",
"license": "UNLICENSED",
"dependencies": {
"@babel/runtime": "^7.22.11",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "immich",
"version": "1.91.0",
"version": "1.91.3",
"description": "",
"author": "",
"private": true,
+3 -1
View File
@@ -1,6 +1,6 @@
import { AssetType } from '@app/infra/entities';
import { Duration } from 'luxon';
import { extname } from 'node:path';
import { extname, join } from 'node:path';
import pkg from 'src/../../package.json';
export const AUDIT_LOG_MAX_DURATION = Duration.fromObject({ days: 100 });
@@ -58,6 +58,8 @@ export const serverVersion = ServerVersion.fromString(pkg.version);
export const APP_MEDIA_LOCATION = process.env.IMMICH_MEDIA_LOCATION || './upload';
export const WEB_ROOT_PATH = join(process.env.IMMICH_WEB_ROOT || '/usr/src/app/www', 'index.html');
const image: Record<string, string[]> = {
'.3fr': ['image/3fr', 'image/x-hasselblad-3fr'],
'.ari': ['image/ari', 'image/x-arriflex-ari'],
+3 -3
View File
@@ -4,7 +4,7 @@ export enum QueueName {
VIDEO_CONVERSION = 'videoConversion',
OBJECT_TAGGING = 'objectTagging',
RECOGNIZE_FACES = 'recognizeFaces',
CLIP_ENCODING = 'clipEncoding',
SMART_SEARCH = 'smartSearch',
BACKGROUND_TASK = 'backgroundTask',
STORAGE_TEMPLATE_MIGRATION = 'storageTemplateMigration',
MIGRATION = 'migration',
@@ -135,8 +135,8 @@ export const JOBS_TO_QUEUE: Record<JobName, QueueName> = {
[JobName.RECOGNIZE_FACES]: QueueName.RECOGNIZE_FACES,
// clip
[JobName.QUEUE_ENCODE_CLIP]: QueueName.CLIP_ENCODING,
[JobName.ENCODE_CLIP]: QueueName.CLIP_ENCODING,
[JobName.QUEUE_ENCODE_CLIP]: QueueName.SMART_SEARCH,
[JobName.ENCODE_CLIP]: QueueName.SMART_SEARCH,
// XMP sidecars
[JobName.QUEUE_SIDECAR]: QueueName.SIDECAR,
+1 -1
View File
@@ -63,7 +63,7 @@ export class AllJobStatusResponseDto implements Record<QueueName, JobStatusDto>
[QueueName.OBJECT_TAGGING]!: JobStatusDto;
@ApiProperty({ type: JobStatusDto })
[QueueName.CLIP_ENCODING]!: JobStatusDto;
[QueueName.SMART_SEARCH]!: JobStatusDto;
@ApiProperty({ type: JobStatusDto })
[QueueName.STORAGE_TEMPLATE_MIGRATION]!: JobStatusDto;
+5 -5
View File
@@ -97,7 +97,7 @@ describe(JobService.name, () => {
await expect(sut.getAllJobsStatus()).resolves.toEqual({
[QueueName.BACKGROUND_TASK]: expectedJobStatus,
[QueueName.CLIP_ENCODING]: expectedJobStatus,
[QueueName.SMART_SEARCH]: expectedJobStatus,
[QueueName.METADATA_EXTRACTION]: expectedJobStatus,
[QueueName.OBJECT_TAGGING]: expectedJobStatus,
[QueueName.SEARCH]: expectedJobStatus,
@@ -171,7 +171,7 @@ describe(JobService.name, () => {
it('should handle a start clip encoding command', async () => {
jobMock.getQueueStatus.mockResolvedValue({ isActive: false, isPaused: false });
await sut.handleCommand(QueueName.CLIP_ENCODING, { command: JobCommand.START, force: false });
await sut.handleCommand(QueueName.SMART_SEARCH, { command: JobCommand.START, force: false });
expect(jobMock.queue).toHaveBeenCalledWith({ name: JobName.QUEUE_ENCODE_CLIP, data: { force: false } });
});
@@ -232,7 +232,7 @@ describe(JobService.name, () => {
SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({
job: {
[QueueName.BACKGROUND_TASK]: { concurrency: 10 },
[QueueName.CLIP_ENCODING]: { concurrency: 10 },
[QueueName.SMART_SEARCH]: { concurrency: 10 },
[QueueName.METADATA_EXTRACTION]: { concurrency: 10 },
[QueueName.OBJECT_TAGGING]: { concurrency: 10 },
[QueueName.RECOGNIZE_FACES]: { concurrency: 10 },
@@ -247,7 +247,7 @@ describe(JobService.name, () => {
} as SystemConfig);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.BACKGROUND_TASK, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.CLIP_ENCODING, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.SMART_SEARCH, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.METADATA_EXTRACTION, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.OBJECT_TAGGING, 10);
expect(jobMock.setConcurrency).toHaveBeenCalledWith(QueueName.RECOGNIZE_FACES, 10);
@@ -367,7 +367,7 @@ describe(JobService.name, () => {
const featureTests: Array<{ queue: QueueName; feature: FeatureFlag; configKey: SystemConfigKey }> = [
{
queue: QueueName.CLIP_ENCODING,
queue: QueueName.SMART_SEARCH,
feature: FeatureFlag.CLIP_ENCODE,
configKey: SystemConfigKey.MACHINE_LEARNING_CLIP_ENABLED,
},
+1 -1
View File
@@ -98,7 +98,7 @@ export class JobService {
await this.configCore.requireFeature(FeatureFlag.TAG_IMAGE);
return this.jobRepository.queue({ name: JobName.QUEUE_OBJECT_TAGGING, data: { force } });
case QueueName.CLIP_ENCODING:
case QueueName.SMART_SEARCH:
await this.configCore.requireFeature(FeatureFlag.CLIP_ENCODE);
return this.jobRepository.queue({ name: JobName.QUEUE_ENCODE_CLIP, data: { force } });
@@ -81,7 +81,7 @@ export const CLIP_MODEL_INFO: Record<string, ModelInfo> = {
'ViT-H-14-quickgelu__dfn5b': {
dimSize: 1024,
},
'ViT-H-14-378-quickgelu__dfn5b ': {
'ViT-H-14-378-quickgelu__dfn5b': {
dimSize: 1024,
},
'ViT-g-14__laion2b-s12b-b42k': {
@@ -29,13 +29,13 @@ export class SmartInfoService {
}
async init() {
await this.jobRepository.pause(QueueName.CLIP_ENCODING);
await this.jobRepository.pause(QueueName.SMART_SEARCH);
let { isActive } = await this.jobRepository.getQueueStatus(QueueName.CLIP_ENCODING);
let { isActive } = await this.jobRepository.getQueueStatus(QueueName.SMART_SEARCH);
while (isActive) {
this.logger.verbose('Waiting for CLIP encoding queue to stop...');
await setTimeout(1000).then(async () => {
({ isActive } = await this.jobRepository.getQueueStatus(QueueName.CLIP_ENCODING));
({ isActive } = await this.jobRepository.getQueueStatus(QueueName.SMART_SEARCH));
});
}
@@ -43,7 +43,7 @@ export class SmartInfoService {
await this.repository.init(machineLearning.clip.modelName);
await this.jobRepository.resume(QueueName.CLIP_ENCODING);
await this.jobRepository.resume(QueueName.SMART_SEARCH);
}
async handleQueueObjectTagging({ force }: IBaseJob) {
@@ -39,7 +39,7 @@ export class SystemConfigJobDto implements Record<QueueName, JobSettingsDto> {
@ValidateNested()
@IsObject()
@Type(() => JobSettingsDto)
[QueueName.CLIP_ENCODING]!: JobSettingsDto;
[QueueName.SMART_SEARCH]!: JobSettingsDto;
@ApiProperty({ type: JobSettingsDto })
@ValidateNested()
@@ -47,7 +47,7 @@ export const defaults = Object.freeze<SystemConfig>({
},
job: {
[QueueName.BACKGROUND_TASK]: { concurrency: 5 },
[QueueName.CLIP_ENCODING]: { concurrency: 2 },
[QueueName.SMART_SEARCH]: { concurrency: 2 },
[QueueName.METADATA_EXTRACTION]: { concurrency: 5 },
[QueueName.OBJECT_TAGGING]: { concurrency: 2 },
[QueueName.RECOGNIZE_FACES]: { concurrency: 2 },
@@ -27,7 +27,7 @@ const updates: SystemConfigEntity[] = [
const updatedConfig = Object.freeze<SystemConfig>({
job: {
[QueueName.BACKGROUND_TASK]: { concurrency: 5 },
[QueueName.CLIP_ENCODING]: { concurrency: 2 },
[QueueName.SMART_SEARCH]: { concurrency: 2 },
[QueueName.METADATA_EXTRACTION]: { concurrency: 5 },
[QueueName.OBJECT_TAGGING]: { concurrency: 2 },
[QueueName.RECOGNIZE_FACES]: { concurrency: 2 },
+2 -1
View File
@@ -7,6 +7,7 @@ import {
SharedLinkService,
StorageService,
SystemConfigService,
WEB_ROOT_PATH,
} from '@app/domain';
import { ImmichLogger } from '@app/infra/logger';
import { Injectable } from '@nestjs/common';
@@ -67,7 +68,7 @@ export class AppService {
ssr(excludePaths: string[]) {
let index = '';
try {
index = readFileSync('/usr/src/app/www/index.html').toString();
index = readFileSync(WEB_ROOT_PATH).toString();
} catch (error: Error | any) {
this.logger.warn('Unable to open `www/index.html, skipping SSR.');
}
@@ -37,7 +37,7 @@ export enum SystemConfigKey {
JOB_VIDEO_CONVERSION_CONCURRENCY = 'job.videoConversion.concurrency',
JOB_OBJECT_TAGGING_CONCURRENCY = 'job.objectTagging.concurrency',
JOB_RECOGNIZE_FACES_CONCURRENCY = 'job.recognizeFaces.concurrency',
JOB_CLIP_ENCODING_CONCURRENCY = 'job.clipEncoding.concurrency',
JOB_CLIP_ENCODING_CONCURRENCY = 'job.smartSearch.concurrency',
JOB_BACKGROUND_TASK_CONCURRENCY = 'job.backgroundTask.concurrency',
JOB_STORAGE_TEMPLATE_MIGRATION_CONCURRENCY = 'job.storageTemplateMigration.concurrency',
JOB_SEARCH_CONCURRENCY = 'job.search.concurrency',
@@ -1,3 +1,4 @@
import { getCLIPModelInfo } from '@app/domain/smart-info/smart-info.constant';
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UsePgVectors1700713871511 implements MigrationInterface {
@@ -8,13 +9,11 @@ export class UsePgVectors1700713871511 implements MigrationInterface {
SELECT CARDINALITY(embedding::real[]) as dimsize
FROM asset_faces
LIMIT 1`);
const clipDimQuery = await queryRunner.query(`
SELECT CARDINALITY("clipEmbedding"::real[]) as dimsize
FROM smart_info
LIMIT 1`);
const faceDimSize = faceDimQuery?.[0]?.['dimsize'] ?? 512;
const clipDimSize = clipDimQuery?.[0]?.['dimsize'] ?? 512;
const clipModelNameQuery = await queryRunner.query(`SELECT value FROM system_config WHERE key = 'machineLearning.clip.modelName'`);
const clipModelName: string = clipModelNameQuery?.[0]?.['value'] ?? 'ViT-B-32__openai';
const clipDimSize = getCLIPModelInfo(clipModelName.replace(/"/g, '')).dimSize;
await queryRunner.query('CREATE EXTENSION IF NOT EXISTS vectors');
@@ -32,7 +31,9 @@ export class UsePgVectors1700713871511 implements MigrationInterface {
INSERT INTO smart_search("assetId", embedding)
SELECT si."assetId", si."clipEmbedding"
FROM smart_info si
WHERE "clipEmbedding" IS NOT NULL`);
WHERE "clipEmbedding" IS NOT NULL
AND CARDINALITY("clipEmbedding"::real[]) = ${clipDimSize}
AND array_position(si."clipEmbedding", NULL) IS NULL`);
await queryRunner.query(`ALTER TABLE smart_info DROP COLUMN IF EXISTS "clipEmbedding"`);
}
+1 -1
View File
@@ -136,7 +136,7 @@ class ImmichApi {
[JobName.MetadataExtraction]: 'Extract Metadata',
[JobName.Sidecar]: 'Sidecar Metadata',
[JobName.ObjectTagging]: 'Tag Objects',
[JobName.ClipEncoding]: 'Encode Clip',
[JobName.SmartSearch]: 'Smart Search',
[JobName.RecognizeFaces]: 'Recognize Faces',
[JobName.VideoConversion]: 'Transcode Videos',
[JobName.StorageTemplateMigration]: 'Storage Template Migration',
+14 -14
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@@ -355,12 +355,6 @@ export interface AllJobStatusResponseDto {
* @memberof AllJobStatusResponseDto
*/
'backgroundTask': JobStatusDto;
/**
*
* @type {JobStatusDto}
* @memberof AllJobStatusResponseDto
*/
'clipEncoding': JobStatusDto;
/**
*
* @type {JobStatusDto}
@@ -403,6 +397,12 @@ export interface AllJobStatusResponseDto {
* @memberof AllJobStatusResponseDto
*/
'sidecar': JobStatusDto;
/**
*
* @type {JobStatusDto}
* @memberof AllJobStatusResponseDto
*/
'smartSearch': JobStatusDto;
/**
*
* @type {JobStatusDto}
@@ -2017,7 +2017,7 @@ export const JobName = {
VideoConversion: 'videoConversion',
ObjectTagging: 'objectTagging',
RecognizeFaces: 'recognizeFaces',
ClipEncoding: 'clipEncoding',
SmartSearch: 'smartSearch',
BackgroundTask: 'backgroundTask',
StorageTemplateMigration: 'storageTemplateMigration',
Migration: 'migration',
@@ -3785,12 +3785,6 @@ export interface SystemConfigJobDto {
* @memberof SystemConfigJobDto
*/
'backgroundTask': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
* @memberof SystemConfigJobDto
*/
'clipEncoding': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
@@ -3833,6 +3827,12 @@ export interface SystemConfigJobDto {
* @memberof SystemConfigJobDto
*/
'sidecar': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
* @memberof SystemConfigJobDto
*/
'smartSearch': JobSettingsDto;
/**
*
* @type {JobSettingsDto}
+1 -1
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+1 -1
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+1 -1
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+1 -1
View File
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.91.0
* The version of the OpenAPI document: 1.91.3
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+1 -1
View File
@@ -6,7 +6,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />
<link rel="icon" type="image/png" sizes="48x48" href="/favicon-48.png" />
+1
View File
@@ -0,0 +1 @@
<svg fill="#2443c2" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="101px" height="101px" viewBox="0 0 425.963 425.963" xml:space="preserve" stroke="#2443c2"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M213.285,0h-0.608C139.114,0,79.268,59.826,79.268,133.361c0,48.202,21.952,111.817,65.246,189.081 c32.098,57.281,64.646,101.152,64.972,101.588c0.906,1.217,2.334,1.934,3.847,1.934c0.043,0,0.087,0,0.13-0.002 c1.561-0.043,3.002-0.842,3.868-2.143c0.321-0.486,32.637-49.287,64.517-108.976c43.03-80.563,64.848-141.624,64.848-181.482 C346.693,59.825,286.846,0,213.285,0z M274.865,136.62c0,34.124-27.761,61.884-61.885,61.884 c-34.123,0-61.884-27.761-61.884-61.884s27.761-61.884,61.884-61.884C247.104,74.736,274.865,102.497,274.865,136.62z"></path> </g> </g></svg>

After

Width:  |  Height:  |  Size: 944 B

@@ -12,10 +12,10 @@
mdiFileJpgBox,
mdiFileXmlBox,
mdiFolderMove,
mdiImageSearch,
mdiLibraryShelves,
mdiTable,
mdiTagMultiple,
mdiVectorCircle,
mdiVideo,
} from '@mdi/js';
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
@@ -56,12 +56,12 @@
[JobName.ThumbnailGeneration]: {
icon: mdiFileJpgBox,
title: api.getJobName(JobName.ThumbnailGeneration),
subtitle: 'Regenerate JPEG and WebP thumbnails',
subtitle: 'Generate large, small and blurred thumbnails for each asset, as well as thumbnails for each person',
},
[JobName.MetadataExtraction]: {
icon: mdiTable,
title: api.getJobName(JobName.MetadataExtraction),
subtitle: 'Extract metadata information i.e. GPS, resolution...etc',
subtitle: 'Extract metadata information from each asset, such as GPS and resolution',
},
[JobName.Library]: {
icon: mdiLibraryShelves,
@@ -81,26 +81,27 @@
[JobName.ObjectTagging]: {
icon: mdiTagMultiple,
title: api.getJobName(JobName.ObjectTagging),
subtitle: 'Run machine learning to tag objects\nNote that some assets may not have any objects detected',
subtitle:
'Run machine learning on assets to tag objects\nNote that some assets may not have any objects detected',
disabled: !$featureFlags.tagImage,
},
[JobName.ClipEncoding]: {
icon: mdiVectorCircle,
title: api.getJobName(JobName.ClipEncoding),
subtitle: 'Run machine learning to generate clip embeddings',
[JobName.SmartSearch]: {
icon: mdiImageSearch,
title: api.getJobName(JobName.SmartSearch),
subtitle: 'Run machine learning on assets to support smart search',
disabled: !$featureFlags.clipEncode,
},
[JobName.RecognizeFaces]: {
icon: mdiFaceRecognition,
title: api.getJobName(JobName.RecognizeFaces),
subtitle: 'Run machine learning to recognize faces',
subtitle: 'Run machine learning on assets to recognize faces',
handleCommand: handleFaceCommand,
disabled: !$featureFlags.facialRecognition,
},
[JobName.VideoConversion]: {
icon: mdiVideo,
title: api.getJobName(JobName.VideoConversion),
subtitle: 'Transcode videos not in the desired format',
subtitle: 'Transcode videos for wider compatibility with browsers and devices',
},
[JobName.StorageTemplateMigration]: {
icon: mdiFolderMove,
@@ -23,7 +23,7 @@
JobName.Library,
JobName.Sidecar,
JobName.ObjectTagging,
JobName.ClipEncoding,
JobName.SmartSearch,
JobName.RecognizeFaces,
JobName.VideoConversion,
JobName.StorageTemplateMigration,
@@ -12,6 +12,7 @@
import type { ResetOptions } from '$lib/utils/dipatch';
export let newVersionCheckConfig: SystemConfigNewVersionCheckDto; // this is the config that is being edited
export let disabled = false;
let savedConfig: SystemConfigNewVersionCheckDto;
let defaultConfig: SystemConfigNewVersionCheckDto;
@@ -86,11 +87,13 @@
title="ENABLED"
subtitle="Enable period requests to GitHub to check for new releases"
bind:checked={newVersionCheckConfig.enabled}
{disabled}
/>
<SettingButtonsRow
on:reset={({ detail }) => handleReset(detail)}
on:save={saveSetting}
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
{disabled}
/>
</div>
</div>
@@ -42,16 +42,15 @@
/>
{#if disabled}
<span class="slider-disable cursor-not-allowed" />
<span class="slider slider-disabled cursor-not-allowed" />
{:else}
<span class="slider cursor-pointer" />
<span class="slider slider-enabled cursor-pointer" />
{/if}
</label>
</div>
<style>
.slider,
.slider-disable {
.slider {
position: absolute;
top: 0;
left: 0;
@@ -67,8 +66,7 @@
cursor: not-allowed;
}
.slider:before,
.slider-disable:before {
.slider:before {
position: absolute;
content: '';
height: 20px;
@@ -82,18 +80,18 @@
border-radius: 50%;
}
input:checked + .slider-disable {
background-color: gray;
}
input:checked + .slider {
background-color: #adcbfa;
}
input:checked + .slider:before {
-webkit-transform: translateX(18px);
-ms-transform: translateX(18px);
transform: translateX(18px);
background-color: #4250af;
}
input:checked + .slider-disabled {
background-color: gray;
}
input:checked + .slider-enabled {
background-color: #adcbfa;
}
</style>
@@ -569,7 +569,13 @@
{#if latlng && $featureFlags.loaded && $featureFlags.map}
<div class="h-[360px]">
<Map mapMarkers={[{ lat: latlng.lat, lon: latlng.lng, id: asset.id }]} center={latlng} zoom={14} simplified>
<Map
mapMarkers={[{ lat: latlng.lat, lon: latlng.lng, id: asset.id }]}
center={latlng}
zoom={15}
simplified
useLocationPin
>
<svelte:fragment slot="popup" let:marker>
{@const { lat, lon } = marker}
<div class="flex flex-col items-center gap-1">
@@ -20,7 +20,7 @@
import type { GeoJSONSource, LngLatLike, StyleSpecification } from 'maplibre-gl';
import type { Feature, Geometry, GeoJsonProperties, Point } from 'geojson';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiCog } from '@mdi/js';
import { mdiCog, mdiMapMarker } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
export let mapMarkers: MapMarkerResponseDto[];
@@ -29,6 +29,7 @@
export let center: LngLatLike | undefined = undefined;
export let simplified = false;
export let clickable = false;
export let useLocationPin = false;
let map: maplibregl.Map;
let marker: maplibregl.Marker | null = null;
@@ -141,7 +142,7 @@
}),
}}
id="geojson"
cluster={{ radius: 500 }}
cluster={{ radius: 500, maxZoom: 42 }}
>
<MarkerLayer
applyToClusters
@@ -165,11 +166,16 @@
$$slots.popup || handleAssetClick(event.detail.feature.properties.id, map);
}}
>
<img
src={api.getAssetThumbnailUrl(feature.properties?.id)}
class="rounded-full w-[60px] h-[60px] border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-contain bg-immich-primary"
alt={`Image with id ${feature.properties?.id}`}
/>
{#if useLocationPin}
<Icon path={mdiMapMarker} size="60px" class="dark:text-immich-dark-primary text-immich-primary" />
{:else}
<img
src={api.getAssetThumbnailUrl(feature.properties?.id)}
class="rounded-full w-[60px] h-[60px] border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-cover bg-immich-primary"
alt={`Image with id ${feature.properties?.id}`}
/>
{/if}
{#if $$slots.popup}
<Popup openOn="click" closeOnClickOutside>
<slot name="popup" marker={asMarker(feature)} />
@@ -119,7 +119,6 @@
try {
const libraryId = libraries[updateLibraryIndex].id;
await api.libraryApi.updateLibrary({ id: libraryId, updateLibraryDto: { ...event } });
} catch (error) {
handleError(error, 'Unable to update library');
@@ -394,7 +393,7 @@
<div transition:slide={{ duration: 250 }} class="mb-4 ml-4 mr-4">
<LibraryScanSettingsForm
{library}
on:submit={({ detail }) => handleUpdate(detail)}
on:submit={({ detail }) => handleUpdate(detail.library)}
on:cancel={() => (editScanSettings = null)}
/>
</div>
+2 -2
View File
@@ -73,7 +73,7 @@
</div>
<div class="flex flex-row flex-wrap gap-4">
{#each places as item (item.data.id)}
<a class="relative" href="{AppRoute.SEARCH}?{Field.CITY}={item.value}" draggable="false">
<a class="relative" href="{AppRoute.SEARCH}?q={item.value}" draggable="false">
<div
class="flex w-[calc((100vw-(72px+5rem))/2)] max-w-[156px] justify-center overflow-hidden rounded-xl brightness-75 filter"
>
@@ -97,7 +97,7 @@
</div>
<div class="flex flex-row flex-wrap gap-4">
{#each things as item}
<a class="relative" href="{AppRoute.SEARCH}?{Field.OBJECTS}={item.value}" draggable="false">
<a class="relative" href="{AppRoute.SEARCH}?q={item.value}" draggable="false">
<div
class="flex w-[calc((100vw-(72px+5rem))/2)] max-w-[156px] justify-center overflow-hidden rounded-xl brightness-75 filter"
>
@@ -116,7 +116,7 @@
</SettingAccordion>
<SettingAccordion title="Version Check" subtitle="Enable/disable the new version notification">
<NewVersionCheckSettings newVersionCheckConfig={configs.newVersionCheck} />
<NewVersionCheckSettings disabled={$featureFlags.configFile} newVersionCheckConfig={configs.newVersionCheck} />
</SettingAccordion>
<SettingAccordion
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB