Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08f66c2ae5 | ||
|
|
4f38a283b4 | ||
|
|
00771899da | ||
|
|
09402eb6d0 | ||
|
|
d9b5adf0f7 | ||
|
|
a15c799ba3 | ||
|
|
bda9fd9dfe | ||
|
|
19754d4b21 | ||
|
|
62347edf43 | ||
|
|
67f020380f | ||
|
|
0aae9696f6 | ||
|
|
2f95cb89c1 | ||
|
|
cb1201e690 | ||
|
|
a2deba4734 | ||
|
|
ae2608e31d | ||
|
|
d8756f3897 | ||
|
|
7839be3b49 | ||
|
|
94e11d52dc | ||
|
|
05a1283500 | ||
|
|
f8519d60c7 | ||
|
|
899c71f297 | ||
|
|
2aa5f55cbf |
28
cli/src/api/open-api/api.ts
generated
@@ -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}
|
||||
|
||||
2
cli/src/api/open-api/base.ts
generated
@@ -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).
|
||||
|
||||
2
cli/src/api/open-api/common.ts
generated
@@ -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).
|
||||
|
||||
2
cli/src/api/open-api/configuration.ts
generated
@@ -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).
|
||||
|
||||
2
cli/src/api/open-api/index.ts
generated
@@ -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).
|
||||
|
||||
@@ -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
docs/docs/guides/external-library.md
Normal 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" />
|
||||
BIN
docs/docs/guides/img/account-settings.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/docs/guides/img/add-path-button.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
docs/docs/guides/img/add-path-field.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
docs/docs/guides/img/administration-link.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/docs/guides/img/create-external-library-button.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
docs/docs/guides/img/edit-import-paths.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/docs/guides/img/external-path.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/docs/guides/img/job-status.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
docs/docs/guides/img/jobs-tab.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/docs/guides/img/libraries-dropdown.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
docs/docs/guides/img/path-save.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/docs/guides/img/pencil.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
docs/docs/guides/img/scan-new-library-files.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/docs/guides/img/user-avatar.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/docs/guides/img/users-tab.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
docs/_redirects → docs/static/_redirects
vendored
@@ -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
|
||||
|
||||
@@ -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" }
|
||||
]
|
||||
}
|
||||
@@ -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 .
|
||||
|
||||
@@ -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,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"
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 679 KiB |
@@ -169,4 +169,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
COCOAPODS: 1.12.1
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
2
mobile/openapi/README.md
generated
@@ -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
|
||||
|
||||
2
mobile/openapi/doc/AllJobStatusResponseDto.md
generated
@@ -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) | |
|
||||
|
||||
2
mobile/openapi/doc/SystemConfigJobDto.md
generated
@@ -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) | |
|
||||
|
||||
@@ -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',
|
||||
|
||||
6
mobile/openapi/lib/model/job_name.dart
generated
@@ -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;
|
||||
|
||||
18
mobile/openapi/lib/model/system_config_job_dto.dart
generated
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
10
mobile/openapi/test/system_config_job_dto_test.dart
generated
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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",
|
||||
|
||||
4
server/package-lock.json
generated
@@ -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,6 +1,6 @@
|
||||
{
|
||||
"name": "immich",
|
||||
"version": "1.91.0",
|
||||
"version": "1.91.3",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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"`);
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
28
web/src/api/open-api/api.ts
generated
@@ -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}
|
||||
|
||||
2
web/src/api/open-api/base.ts
generated
@@ -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).
|
||||
|
||||
2
web/src/api/open-api/common.ts
generated
@@ -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).
|
||||
|
||||
2
web/src/api/open-api/configuration.ts
generated
@@ -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).
|
||||
|
||||
2
web/src/api/open-api/index.ts
generated
@@ -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).
|
||||
|
||||
@@ -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
web/src/lib/assets/location-pin.svg
Normal 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>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.1 KiB |