Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01ba859567 | ||
|
|
173c9070c8 | ||
|
|
d37e8ede3b |
6
cli/package-lock.json
generated
6
cli/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.9",
|
||||
"version": "2.2.10",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.9",
|
||||
"version": "2.2.10",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"fast-glob": "^3.3.2",
|
||||
@@ -49,7 +49,7 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.9",
|
||||
"version": "2.2.10",
|
||||
"description": "Command Line Interface (CLI) for Immich",
|
||||
"type": "module",
|
||||
"exports": "./dist/index.js",
|
||||
|
||||
@@ -38,17 +38,18 @@ Regardless of filesystem, it is not recommended to use a network share for your
|
||||
|
||||
## General
|
||||
|
||||
| Variable | Description | Default | Containers | Workers |
|
||||
| :---------------------------------- | :---------------------------------------------- | :--------------------------: | :----------------------- | :----------------- |
|
||||
| `TZ` | Timezone | | server | microservices |
|
||||
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
|
||||
| `IMMICH_LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
|
||||
| `IMMICH_MEDIA_LOCATION` | Media Location | `./upload`<sup>\*1</sup> | server | api, microservices |
|
||||
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
|
||||
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
|
||||
| `CPU_CORES` | Amount of cores available to the immich server | auto-detected cpu core count | server | |
|
||||
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
|
||||
| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices |
|
||||
| Variable | Description | Default | Containers | Workers |
|
||||
| :---------------------------------- | :-------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- |
|
||||
| `TZ` | Timezone | | server | microservices |
|
||||
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
|
||||
| `IMMICH_LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
|
||||
| `IMMICH_MEDIA_LOCATION` | Media Location | `./upload`<sup>\*1</sup> | server | api, microservices |
|
||||
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
|
||||
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
|
||||
| `CPU_CORES` | Amount of cores available to the immich server | auto-detected cpu core count | server | |
|
||||
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
|
||||
| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices |
|
||||
| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices |
|
||||
|
||||
\*1: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`.
|
||||
It only need to be set if the Immich deployment method is changing.
|
||||
|
||||
4
docs/static/archived-versions.json
vendored
4
docs/static/archived-versions.json
vendored
@@ -1,4 +1,8 @@
|
||||
[
|
||||
{
|
||||
"label": "v1.109.1",
|
||||
"url": "https://v1.109.1.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.109.0",
|
||||
"url": "https://v1.109.0.archive.immich.app"
|
||||
|
||||
8
e2e/package-lock.json
generated
8
e2e/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich-e2e",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"devDependencies": {
|
||||
"@immich/cli": "file:../cli",
|
||||
@@ -42,7 +42,7 @@
|
||||
},
|
||||
"../cli": {
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.9",
|
||||
"version": "2.2.10",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
@@ -86,7 +86,7 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "machine-learning"
|
||||
version = "1.109.0"
|
||||
version = "1.109.1"
|
||||
description = ""
|
||||
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -12,6 +12,7 @@ fi
|
||||
|
||||
: "${IMMICH_HOST:=[::]}"
|
||||
: "${IMMICH_PORT:=3003}"
|
||||
: "${MACHINE_LEARNING_WORKERS:=1}"
|
||||
|
||||
gunicorn app.main:app \
|
||||
-k app.config.CustomUvicornWorker \
|
||||
|
||||
@@ -36,7 +36,7 @@ platform :android do
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 149,
|
||||
"android.injected.version.name" => "1.109.0",
|
||||
"android.injected.version.name" => "1.109.1",
|
||||
}
|
||||
)
|
||||
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')
|
||||
|
||||
@@ -19,7 +19,7 @@ platform :ios do
|
||||
desc "iOS Release"
|
||||
lane :release do
|
||||
increment_version_number(
|
||||
version_number: "1.109.0"
|
||||
version_number: "1.109.1"
|
||||
)
|
||||
increment_build_number(
|
||||
build_number: latest_testflight_build_number + 1,
|
||||
|
||||
2
mobile/openapi/README.md
generated
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.109.0
|
||||
- API version: 1.109.1
|
||||
- Generator version: 7.5.0
|
||||
- Build package: org.openapitools.codegen.languages.DartClientCodegen
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ name: immich_mobile
|
||||
description: Immich - selfhosted backup media file on mobile phone
|
||||
|
||||
publish_to: 'none'
|
||||
version: 1.109.0+149
|
||||
version: 1.109.1+149
|
||||
|
||||
environment:
|
||||
sdk: '>=3.3.0 <4.0.0'
|
||||
|
||||
@@ -7007,7 +7007,7 @@
|
||||
"info": {
|
||||
"title": "Immich",
|
||||
"description": "Immich API",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"contact": {}
|
||||
},
|
||||
"tags": [],
|
||||
|
||||
4
open-api/typescript-sdk/package-lock.json
generated
4
open-api/typescript-sdk/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"description": "Auto-generated TypeScript SDK for the Immich API",
|
||||
"type": "module",
|
||||
"main": "./build/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Immich
|
||||
* 1.109.0
|
||||
* 1.109.1
|
||||
* DO NOT MODIFY - This file has been generated using oazapfts.
|
||||
* See https://www.npmjs.com/package/oazapfts
|
||||
*/
|
||||
|
||||
4
server/package-lock.json
generated
4
server/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "immich",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@nestjs/bullmq": "^10.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface ThumbnailOptions {
|
||||
colorspace: string;
|
||||
quality: number;
|
||||
crop?: CropOptions;
|
||||
processInvalidImages: boolean;
|
||||
}
|
||||
|
||||
export interface VideoStreamInfo {
|
||||
|
||||
@@ -45,7 +45,8 @@ export class MediaRepository implements IMediaRepository {
|
||||
}
|
||||
|
||||
async generateThumbnail(input: string | Buffer, output: string, options: ThumbnailOptions): Promise<void> {
|
||||
const pipeline = sharp(input, { failOn: 'error', limitInputPixels: false })
|
||||
// some invalid images can still be processed by sharp, but we want to fail on them by default to avoid crashes
|
||||
const pipeline = sharp(input, { failOn: options.processInvalidImages ? 'none' : 'error', limitInputPixels: false })
|
||||
.pipelineColorspace(options.colorspace === Colorspace.SRGB ? 'srgb' : 'rgb16')
|
||||
.rotate();
|
||||
|
||||
|
||||
@@ -296,6 +296,7 @@ describe(MediaService.name, () => {
|
||||
format,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.SRGB,
|
||||
processInvalidImages: false,
|
||||
});
|
||||
expect(assetMock.update).toHaveBeenCalledWith({ id: 'asset-id', previewPath });
|
||||
});
|
||||
@@ -326,6 +327,7 @@ describe(MediaService.name, () => {
|
||||
format: ImageFormat.JPEG,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
processInvalidImages: false,
|
||||
},
|
||||
);
|
||||
expect(assetMock.update).toHaveBeenCalledWith({
|
||||
@@ -468,6 +470,7 @@ describe(MediaService.name, () => {
|
||||
format,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.SRGB,
|
||||
processInvalidImages: false,
|
||||
});
|
||||
expect(assetMock.update).toHaveBeenCalledWith({ id: 'asset-id', thumbnailPath });
|
||||
},
|
||||
@@ -498,6 +501,7 @@ describe(MediaService.name, () => {
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
processInvalidImages: false,
|
||||
},
|
||||
);
|
||||
expect(assetMock.update).toHaveBeenCalledWith({
|
||||
@@ -524,6 +528,7 @@ describe(MediaService.name, () => {
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
processInvalidImages: false,
|
||||
},
|
||||
],
|
||||
]);
|
||||
@@ -548,6 +553,7 @@ describe(MediaService.name, () => {
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
processInvalidImages: false,
|
||||
},
|
||||
],
|
||||
]);
|
||||
@@ -570,6 +576,7 @@ describe(MediaService.name, () => {
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
processInvalidImages: false,
|
||||
},
|
||||
);
|
||||
expect(mediaMock.getImageDimensions).not.toHaveBeenCalled();
|
||||
@@ -590,11 +597,34 @@ describe(MediaService.name, () => {
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
processInvalidImages: false,
|
||||
},
|
||||
);
|
||||
expect(mediaMock.getImageDimensions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should process invalid images if enabled', async () => {
|
||||
vi.stubEnv('IMMICH_PROCESS_INVALID_IMAGES', 'true');
|
||||
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.imageDng]);
|
||||
|
||||
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
|
||||
|
||||
expect(mediaMock.generateThumbnail).toHaveBeenCalledWith(
|
||||
assetStub.imageDng.originalPath,
|
||||
'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
|
||||
{
|
||||
format: ImageFormat.WEBP,
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
processInvalidImages: true,
|
||||
},
|
||||
);
|
||||
expect(mediaMock.getImageDimensions).not.toHaveBeenCalled();
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
describe('handleGenerateThumbhash', () => {
|
||||
it('should skip thumbhash generation if asset not found', async () => {
|
||||
assetMock.getByIds.mockResolvedValue([]);
|
||||
|
||||
@@ -199,7 +199,13 @@ export class MediaService {
|
||||
try {
|
||||
const useExtracted = didExtract && (await this.shouldUseExtractedImage(extractedPath, image.previewSize));
|
||||
const colorspace = this.isSRGB(asset) ? Colorspace.SRGB : image.colorspace;
|
||||
const imageOptions = { format, size, colorspace, quality: image.quality };
|
||||
const imageOptions = {
|
||||
format,
|
||||
size,
|
||||
colorspace,
|
||||
quality: image.quality,
|
||||
processInvalidImages: process.env.IMMICH_PROCESS_INVALID_IMAGES === 'true',
|
||||
};
|
||||
|
||||
const outputPath = useExtracted ? extractedPath : asset.originalPath;
|
||||
await this.mediaRepository.generateThumbnail(outputPath, path, imageOptions);
|
||||
|
||||
@@ -958,6 +958,7 @@ describe(PersonService.name, () => {
|
||||
width: 274,
|
||||
height: 274,
|
||||
},
|
||||
processInvalidImages: false,
|
||||
},
|
||||
);
|
||||
expect(personMock.update).toHaveBeenCalledWith({
|
||||
@@ -987,6 +988,7 @@ describe(PersonService.name, () => {
|
||||
width: 510,
|
||||
height: 510,
|
||||
},
|
||||
processInvalidImages: false,
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -1012,6 +1014,7 @@ describe(PersonService.name, () => {
|
||||
width: 408,
|
||||
height: 408,
|
||||
},
|
||||
processInvalidImages: false,
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -1038,6 +1041,7 @@ describe(PersonService.name, () => {
|
||||
width: 588,
|
||||
height: 588,
|
||||
},
|
||||
processInvalidImages: false,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -559,6 +559,7 @@ export class PersonService {
|
||||
colorspace: image.colorspace,
|
||||
quality: image.quality,
|
||||
crop: this.getCrop({ old: { width: oldWidth, height: oldHeight }, new: { width, height } }, { x1, y1, x2, y2 }),
|
||||
processInvalidImages: process.env.IMMICH_PROCESS_INVALID_IMAGES === 'true',
|
||||
} as const;
|
||||
|
||||
await this.mediaRepository.generateThumbnail(inputPath, thumbnailPath, thumbnailOptions);
|
||||
|
||||
6
web/package-lock.json
generated
6
web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "immich-web",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich-web",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@formatjs/icu-messageformat-parser": "^2.7.8",
|
||||
@@ -70,7 +70,7 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-web",
|
||||
"version": "1.109.0",
|
||||
"version": "1.109.1",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"scripts": {
|
||||
"dev": "vite dev --host 0.0.0.0 --port 3000",
|
||||
|
||||
Reference in New Issue
Block a user