diff --git a/cli/package-lock.json b/cli/package-lock.json index 4f8b28168d..f6e514644c 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -1,12 +1,12 @@ { "name": "@immich/cli", - "version": "2.2.29", + "version": "2.2.30", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@immich/cli", - "version": "2.2.29", + "version": "2.2.30", "license": "GNU Affero General Public License version 3", "dependencies": { "fast-glob": "^3.3.2", @@ -52,7 +52,7 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.120.0", + "version": "1.120.1", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { diff --git a/cli/package.json b/cli/package.json index ab7db104f6..5caa25778e 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@immich/cli", - "version": "2.2.29", + "version": "2.2.30", "description": "Command Line Interface (CLI) for Immich", "type": "module", "exports": "./dist/index.js", diff --git a/docs/static/archived-versions.json b/docs/static/archived-versions.json index 86570d9ce3..52ce0d57e5 100644 --- a/docs/static/archived-versions.json +++ b/docs/static/archived-versions.json @@ -1,4 +1,8 @@ [ + { + "label": "v1.120.1", + "url": "https://v1.120.1.archive.immich.app" + }, { "label": "v1.120.0", "url": "https://v1.120.0.archive.immich.app" diff --git a/e2e/package-lock.json b/e2e/package-lock.json index eb17fe1e1a..0357d6e507 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich-e2e", - "version": "1.120.0", + "version": "1.120.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich-e2e", - "version": "1.120.0", + "version": "1.120.1", "license": "GNU Affero General Public License version 3", "devDependencies": { "@eslint/eslintrc": "^3.1.0", @@ -45,7 +45,7 @@ }, "../cli": { "name": "@immich/cli", - "version": "2.2.29", + "version": "2.2.30", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { @@ -92,7 +92,7 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.120.0", + "version": "1.120.1", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { diff --git a/e2e/package.json b/e2e/package.json index f2afa1f00d..c1a5227f93 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -1,6 +1,6 @@ { "name": "immich-e2e", - "version": "1.120.0", + "version": "1.120.1", "description": "", "main": "index.js", "type": "module", diff --git a/e2e/src/api/specs/search.e2e-spec.ts b/e2e/src/api/specs/search.e2e-spec.ts index 0e5d882f80..627fbb3e9e 100644 --- a/e2e/src/api/specs/search.e2e-spec.ts +++ b/e2e/src/api/specs/search.e2e-spec.ts @@ -473,10 +473,7 @@ describe('/search', () => { .get('/search/explore') .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); - expect(body).toEqual([ - { fieldName: 'exifInfo.city', items: [] }, - { fieldName: 'smartInfo.tags', items: [] }, - ]); + expect(body).toEqual([{ fieldName: 'exifInfo.city', items: [] }]); }); }); diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml index 4286b9e5d4..2b64a00ebe 100644 --- a/machine-learning/pyproject.toml +++ b/machine-learning/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "machine-learning" -version = "1.120.0" +version = "1.120.1" description = "" authors = ["Hau Tran "] readme = "README.md" diff --git a/mobile/android/fastlane/Fastfile b/mobile/android/fastlane/Fastfile index 1477ca2575..6a3df82f07 100644 --- a/mobile/android/fastlane/Fastfile +++ b/mobile/android/fastlane/Fastfile @@ -35,8 +35,8 @@ platform :android do task: 'bundle', build_type: 'Release', properties: { - "android.injected.version.code" => 165, - "android.injected.version.name" => "1.120.0", + "android.injected.version.code" => 166, + "android.injected.version.name" => "1.120.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') diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index c8cc4d9227..6c233a7e29 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -401,7 +401,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 182; + CURRENT_PROJECT_VERSION = 183; 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 = 182; + CURRENT_PROJECT_VERSION = 183; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -571,7 +571,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 182; + CURRENT_PROJECT_VERSION = 183; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index ef15a45a7c..2887a17c73 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -58,11 +58,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.120.0 + 1.120.1 CFBundleSignature ???? CFBundleVersion - 182 + 183 FLTEnableImpeller ITSAppUsesNonExemptEncryption diff --git a/mobile/ios/fastlane/Fastfile b/mobile/ios/fastlane/Fastfile index 70308e97e1..a08ad49208 100644 --- a/mobile/ios/fastlane/Fastfile +++ b/mobile/ios/fastlane/Fastfile @@ -19,7 +19,7 @@ platform :ios do desc "iOS Release" lane :release do increment_version_number( - version_number: "1.120.0" + version_number: "1.120.1" ) increment_build_number( build_number: latest_testflight_build_number + 1, diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index bcac50e93d..fff9a5659e 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -3,7 +3,7 @@ Immich API This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: -- API version: 1.120.0 +- API version: 1.120.1 - Generator version: 7.8.0 - Build package: org.openapitools.codegen.languages.DartClientCodegen @@ -409,7 +409,6 @@ Class | Method | HTTP request | Description - [SharedLinkResponseDto](doc//SharedLinkResponseDto.md) - [SharedLinkType](doc//SharedLinkType.md) - [SignUpDto](doc//SignUpDto.md) - - [SmartInfoResponseDto](doc//SmartInfoResponseDto.md) - [SmartSearchDto](doc//SmartSearchDto.md) - [SourceType](doc//SourceType.md) - [StackCreateDto](doc//StackCreateDto.md) diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 65fca58f90..73eb02d89e 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -222,7 +222,6 @@ part 'model/shared_link_edit_dto.dart'; part 'model/shared_link_response_dto.dart'; part 'model/shared_link_type.dart'; part 'model/sign_up_dto.dart'; -part 'model/smart_info_response_dto.dart'; part 'model/smart_search_dto.dart'; part 'model/source_type.dart'; part 'model/stack_create_dto.dart'; diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 3a6623b910..a6f8d551da 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -498,8 +498,6 @@ class ApiClient { return SharedLinkTypeTypeTransformer().decode(value); case 'SignUpDto': return SignUpDto.fromJson(value); - case 'SmartInfoResponseDto': - return SmartInfoResponseDto.fromJson(value); case 'SmartSearchDto': return SmartSearchDto.fromJson(value); case 'SourceType': diff --git a/mobile/openapi/lib/model/asset_response_dto.dart b/mobile/openapi/lib/model/asset_response_dto.dart index c11dedcbfd..5f01f84419 100644 --- a/mobile/openapi/lib/model/asset_response_dto.dart +++ b/mobile/openapi/lib/model/asset_response_dto.dart @@ -37,7 +37,6 @@ class AssetResponseDto { required this.ownerId, this.people = const [], this.resized, - this.smartInfo, this.stack, this.tags = const [], required this.thumbhash, @@ -121,14 +120,6 @@ class AssetResponseDto { /// bool? resized; - /// - /// Please note: This property should have been non-nullable! Since the specification file - /// does not include a default value (using the "default:" property), however, the generated - /// source code must fall back to having a nullable type. - /// Consider adding a "default:" property in the specification file to hide this note. - /// - SmartInfoResponseDto? smartInfo; - AssetStackResponseDto? stack; List tags; @@ -167,7 +158,6 @@ class AssetResponseDto { other.ownerId == ownerId && _deepEquality.equals(other.people, people) && other.resized == resized && - other.smartInfo == smartInfo && other.stack == stack && _deepEquality.equals(other.tags, tags) && other.thumbhash == thumbhash && @@ -202,7 +192,6 @@ class AssetResponseDto { (ownerId.hashCode) + (people.hashCode) + (resized == null ? 0 : resized!.hashCode) + - (smartInfo == null ? 0 : smartInfo!.hashCode) + (stack == null ? 0 : stack!.hashCode) + (tags.hashCode) + (thumbhash == null ? 0 : thumbhash!.hashCode) + @@ -211,7 +200,7 @@ class AssetResponseDto { (updatedAt.hashCode); @override - String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duplicateId=$duplicateId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isFavorite=$isFavorite, isOffline=$isOffline, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalMimeType=$originalMimeType, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, stack=$stack, tags=$tags, thumbhash=$thumbhash, type=$type, unassignedFaces=$unassignedFaces, updatedAt=$updatedAt]'; + String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duplicateId=$duplicateId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isFavorite=$isFavorite, isOffline=$isOffline, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalMimeType=$originalMimeType, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, stack=$stack, tags=$tags, thumbhash=$thumbhash, type=$type, unassignedFaces=$unassignedFaces, updatedAt=$updatedAt]'; Map toJson() { final json = {}; @@ -267,11 +256,6 @@ class AssetResponseDto { } else { // json[r'resized'] = null; } - if (this.smartInfo != null) { - json[r'smartInfo'] = this.smartInfo; - } else { - // json[r'smartInfo'] = null; - } if (this.stack != null) { json[r'stack'] = this.stack; } else { @@ -322,7 +306,6 @@ class AssetResponseDto { ownerId: mapValueOfType(json, r'ownerId')!, people: PersonWithFacesResponseDto.listFromJson(json[r'people']), resized: mapValueOfType(json, r'resized'), - smartInfo: SmartInfoResponseDto.fromJson(json[r'smartInfo']), stack: AssetStackResponseDto.fromJson(json[r'stack']), tags: TagResponseDto.listFromJson(json[r'tags']), thumbhash: mapValueOfType(json, r'thumbhash'), diff --git a/mobile/openapi/lib/model/smart_info_response_dto.dart b/mobile/openapi/lib/model/smart_info_response_dto.dart deleted file mode 100644 index 4631eccf2c..0000000000 --- a/mobile/openapi/lib/model/smart_info_response_dto.dart +++ /dev/null @@ -1,117 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.18 - -// ignore_for_file: unused_element, unused_import -// ignore_for_file: always_put_required_named_parameters_first -// ignore_for_file: constant_identifier_names -// ignore_for_file: lines_longer_than_80_chars - -part of openapi.api; - -class SmartInfoResponseDto { - /// Returns a new [SmartInfoResponseDto] instance. - SmartInfoResponseDto({ - this.objects = const [], - this.tags = const [], - }); - - List? objects; - - List? tags; - - @override - bool operator ==(Object other) => identical(this, other) || other is SmartInfoResponseDto && - _deepEquality.equals(other.objects, objects) && - _deepEquality.equals(other.tags, tags); - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (objects == null ? 0 : objects!.hashCode) + - (tags == null ? 0 : tags!.hashCode); - - @override - String toString() => 'SmartInfoResponseDto[objects=$objects, tags=$tags]'; - - Map toJson() { - final json = {}; - if (this.objects != null) { - json[r'objects'] = this.objects; - } else { - // json[r'objects'] = null; - } - if (this.tags != null) { - json[r'tags'] = this.tags; - } else { - // json[r'tags'] = null; - } - return json; - } - - /// Returns a new [SmartInfoResponseDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static SmartInfoResponseDto? fromJson(dynamic value) { - upgradeDto(value, "SmartInfoResponseDto"); - if (value is Map) { - final json = value.cast(); - - return SmartInfoResponseDto( - objects: json[r'objects'] is Iterable - ? (json[r'objects'] as Iterable).cast().toList(growable: false) - : const [], - tags: json[r'tags'] is Iterable - ? (json[r'tags'] as Iterable).cast().toList(growable: false) - : const [], - ); - } - return null; - } - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = SmartInfoResponseDto.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } - - static Map mapFromJson(dynamic json) { - final map = {}; - if (json is Map && json.isNotEmpty) { - json = json.cast(); // ignore: parameter_assignments - for (final entry in json.entries) { - final value = SmartInfoResponseDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of SmartInfoResponseDto-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; - if (json is Map && json.isNotEmpty) { - // ignore: parameter_assignments - json = json.cast(); - for (final entry in json.entries) { - map[entry.key] = SmartInfoResponseDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - }; -} - diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index a556e99b13..bf75dad455 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -2,7 +2,7 @@ name: immich_mobile description: Immich - selfhosted backup media file on mobile phone publish_to: 'none' -version: 1.120.0+165 +version: 1.120.1+166 environment: sdk: '>=3.3.0 <4.0.0' diff --git a/mobile/scripts/fdroid_build_isar.sh b/mobile/scripts/fdroid_build_isar.sh index 41517737c9..f42bc51d9a 100755 --- a/mobile/scripts/fdroid_build_isar.sh +++ b/mobile/scripts/fdroid_build_isar.sh @@ -8,11 +8,11 @@ bash tool/build_android.sh x64 bash tool/build_android.sh armv7 bash tool/build_android.sh arm64 mv libisar_android_arm64.so libisar.so -mv libisar.so ../.pub-cache/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/arm64-v8a/ +mv libisar.so ../.pub-cache/hosted/pub.isar-community.dev/isar_flutter_libs-*/android/src/main/jniLibs/arm64-v8a/ mv libisar_android_armv7.so libisar.so -mv libisar.so ../.pub-cache/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/armeabi-v7a/ +mv libisar.so ../.pub-cache/hosted/pub.isar-community.dev/isar_flutter_libs-*/android/src/main/jniLibs/armeabi-v7a/ mv libisar_android_x64.so libisar.so -mv libisar.so ../.pub-cache/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86_64/ +mv libisar.so ../.pub-cache/hosted/pub.isar-community.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86_64/ mv libisar_android_x86.so libisar.so -mv libisar.so ../.pub-cache/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86/ +mv libisar.so ../.pub-cache/hosted/pub.isar-community.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86/ ) \ No newline at end of file diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 9ea0c6a277..cb5a04c791 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -7436,7 +7436,7 @@ "info": { "title": "Immich", "description": "Immich API", - "version": "1.120.0", + "version": "1.120.1", "contact": {} }, "tags": [], @@ -8453,9 +8453,6 @@ "description": "This property was deprecated in v1.113.0", "type": "boolean" }, - "smartInfo": { - "$ref": "#/components/schemas/SmartInfoResponseDto" - }, "stack": { "allOf": [ { @@ -11335,25 +11332,6 @@ ], "type": "object" }, - "SmartInfoResponseDto": { - "properties": { - "objects": { - "items": { - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "tags": { - "items": { - "type": "string" - }, - "nullable": true, - "type": "array" - } - }, - "type": "object" - }, "SmartSearchDto": { "properties": { "city": { diff --git a/open-api/typescript-sdk/package-lock.json b/open-api/typescript-sdk/package-lock.json index 10d4b1078a..d7f3059b80 100644 --- a/open-api/typescript-sdk/package-lock.json +++ b/open-api/typescript-sdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "@immich/sdk", - "version": "1.120.0", + "version": "1.120.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@immich/sdk", - "version": "1.120.0", + "version": "1.120.1", "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" diff --git a/open-api/typescript-sdk/package.json b/open-api/typescript-sdk/package.json index aadc1bc8b6..0cf484196d 100644 --- a/open-api/typescript-sdk/package.json +++ b/open-api/typescript-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@immich/sdk", - "version": "1.120.0", + "version": "1.120.1", "description": "Auto-generated TypeScript SDK for the Immich API", "type": "module", "main": "./build/index.js", diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index 08e38bfe27..8d56eb4d2b 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1,6 +1,6 @@ /** * Immich - * 1.120.0 + * 1.120.1 * DO NOT MODIFY - This file has been generated using oazapfts. * See https://www.npmjs.com/package/oazapfts */ @@ -221,10 +221,6 @@ export type PersonWithFacesResponseDto = { /** This property was added in v1.107.0 */ updatedAt?: string; }; -export type SmartInfoResponseDto = { - objects?: string[] | null; - tags?: string[] | null; -}; export type AssetStackResponseDto = { assetCount: number; id: string; @@ -267,7 +263,6 @@ export type AssetResponseDto = { people?: PersonWithFacesResponseDto[]; /** This property was deprecated in v1.113.0 */ resized?: boolean; - smartInfo?: SmartInfoResponseDto; stack?: (AssetStackResponseDto) | null; tags?: TagResponseDto[]; thumbhash: string | null; diff --git a/server/package-lock.json b/server/package-lock.json index 7586c1f045..19398bb59d 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich", - "version": "1.120.0", + "version": "1.120.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "immich", - "version": "1.120.0", + "version": "1.120.1", "license": "GNU Affero General Public License version 3", "dependencies": { "@nestjs/bullmq": "^10.0.1", diff --git a/server/package.json b/server/package.json index 1f4b65fa57..1ef0da4942 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "immich", - "version": "1.120.0", + "version": "1.120.1", "description": "", "author": "", "private": true, diff --git a/server/src/dtos/asset-response.dto.ts b/server/src/dtos/asset-response.dto.ts index ed92208182..a255ac103b 100644 --- a/server/src/dtos/asset-response.dto.ts +++ b/server/src/dtos/asset-response.dto.ts @@ -12,7 +12,6 @@ import { TagResponseDto, mapTag } from 'src/dtos/tag.dto'; import { UserResponseDto, mapUser } from 'src/dtos/user.dto'; import { AssetFaceEntity } from 'src/entities/asset-face.entity'; import { AssetEntity } from 'src/entities/asset.entity'; -import { SmartInfoEntity } from 'src/entities/smart-info.entity'; import { AssetType } from 'src/enum'; import { mimeTypes } from 'src/utils/mime-types'; @@ -45,7 +44,6 @@ export class AssetResponseDto extends SanitizedAssetResponseDto { isTrashed!: boolean; isOffline!: boolean; exifInfo?: ExifResponseDto; - smartInfo?: SmartInfoResponseDto; tags?: TagResponseDto[]; people?: PersonWithFacesResponseDto[]; unassignedFaces?: AssetFaceWithoutPersonResponseDto[]; @@ -141,7 +139,6 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As isTrashed: !!entity.deletedAt, duration: entity.duration ?? '0:00:00.00000', exifInfo: entity.exifInfo ? mapExif(entity.exifInfo) : undefined, - smartInfo: entity.smartInfo ? mapSmartInfo(entity.smartInfo) : undefined, livePhotoVideoId: entity.livePhotoVideoId, tags: entity.tags?.map((tag) => mapTag(tag)), people: peopleWithFaces(entity.faces), @@ -161,15 +158,3 @@ export class MemoryLaneResponseDto { assets!: AssetResponseDto[]; } - -export class SmartInfoResponseDto { - tags?: string[] | null; - objects?: string[] | null; -} - -export function mapSmartInfo(entity: SmartInfoEntity): SmartInfoResponseDto { - return { - tags: entity.tags, - objects: entity.objects, - }; -} diff --git a/server/src/entities/asset.entity.ts b/server/src/entities/asset.entity.ts index 0b893134d0..f9e5c5e981 100644 --- a/server/src/entities/asset.entity.ts +++ b/server/src/entities/asset.entity.ts @@ -5,7 +5,6 @@ import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity'; import { ExifEntity } from 'src/entities/exif.entity'; import { LibraryEntity } from 'src/entities/library.entity'; import { SharedLinkEntity } from 'src/entities/shared-link.entity'; -import { SmartInfoEntity } from 'src/entities/smart-info.entity'; import { SmartSearchEntity } from 'src/entities/smart-search.entity'; import { StackEntity } from 'src/entities/stack.entity'; import { TagEntity } from 'src/entities/tag.entity'; @@ -143,9 +142,6 @@ export class AssetEntity { @OneToOne(() => ExifEntity, (exifEntity) => exifEntity.asset) exifInfo?: ExifEntity; - @OneToOne(() => SmartInfoEntity, (smartInfoEntity) => smartInfoEntity.asset) - smartInfo?: SmartInfoEntity; - @OneToOne(() => SmartSearchEntity, (smartSearchEntity) => smartSearchEntity.asset) smartSearch?: SmartSearchEntity; diff --git a/server/src/entities/index.ts b/server/src/entities/index.ts index 7425ee67d8..75e92038ac 100644 --- a/server/src/entities/index.ts +++ b/server/src/entities/index.ts @@ -18,7 +18,6 @@ import { PartnerEntity } from 'src/entities/partner.entity'; import { PersonEntity } from 'src/entities/person.entity'; import { SessionEntity } from 'src/entities/session.entity'; import { SharedLinkEntity } from 'src/entities/shared-link.entity'; -import { SmartInfoEntity } from 'src/entities/smart-info.entity'; import { SmartSearchEntity } from 'src/entities/smart-search.entity'; import { StackEntity } from 'src/entities/stack.entity'; import { SystemMetadataEntity } from 'src/entities/system-metadata.entity'; @@ -46,7 +45,6 @@ export const entities = [ PartnerEntity, PersonEntity, SharedLinkEntity, - SmartInfoEntity, SmartSearchEntity, StackEntity, SystemMetadataEntity, diff --git a/server/src/entities/smart-info.entity.ts b/server/src/entities/smart-info.entity.ts deleted file mode 100644 index 86190c174d..0000000000 --- a/server/src/entities/smart-info.entity.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { AssetEntity } from 'src/entities/asset.entity'; -import { Column, Entity, JoinColumn, OneToOne, PrimaryColumn } from 'typeorm'; - -@Entity('smart_info', { synchronize: false }) -export class SmartInfoEntity { - @OneToOne(() => AssetEntity, { onDelete: 'CASCADE', nullable: true }) - @JoinColumn({ name: 'assetId', referencedColumnName: 'id' }) - asset?: AssetEntity; - - @PrimaryColumn() - assetId!: string; - - @Column({ type: 'text', array: true, nullable: true }) - tags!: string[] | null; - - @Column({ type: 'text', array: true, nullable: true }) - objects!: string[] | null; -} diff --git a/server/src/interfaces/asset.interface.ts b/server/src/interfaces/asset.interface.ts index 37d3326a8a..1b32c57d41 100644 --- a/server/src/interfaces/asset.interface.ts +++ b/server/src/interfaces/asset.interface.ts @@ -28,9 +28,7 @@ export enum WithoutProperty { EXIF = 'exif', SMART_SEARCH = 'smart-search', DUPLICATE = 'duplicate', - OBJECT_TAGS = 'object-tags', FACES = 'faces', - PERSON = 'person', SIDECAR = 'sidecar', } @@ -94,7 +92,6 @@ export type AssetWithoutRelations = Omit< | 'library' | 'exifInfo' | 'sharedLinks' - | 'smartInfo' | 'smartSearch' | 'tags' >; @@ -190,7 +187,6 @@ export interface IAssetRepository { upsertExif(exif: Partial): Promise; upsertJobStatus(...jobStatus: Partial[]): Promise; getAssetIdByCity(userId: string, options: AssetExploreFieldOptions): Promise>; - getAssetIdByTag(userId: string, options: AssetExploreFieldOptions): Promise>; getDuplicates(options: AssetBuilderOptions): Promise; getAllForUserFullSync(options: AssetFullSyncOptions): Promise; getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise; diff --git a/server/src/interfaces/search.interface.ts b/server/src/interfaces/search.interface.ts index 63d74a35fb..87bf1bc4b1 100644 --- a/server/src/interfaces/search.interface.ts +++ b/server/src/interfaces/search.interface.ts @@ -68,7 +68,6 @@ export interface SearchStatusOptions { export interface SearchOneToOneRelationOptions { withExif?: boolean; - withSmartInfo?: boolean; withStacked?: boolean; } diff --git a/server/src/migrations/1730989238718-DropSmartInfoTable.ts b/server/src/migrations/1730989238718-DropSmartInfoTable.ts new file mode 100644 index 0000000000..a4de2652d6 --- /dev/null +++ b/server/src/migrations/1730989238718-DropSmartInfoTable.ts @@ -0,0 +1,11 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class DropSmartInfoTable1730989238718 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE smart_info`); + } + + public async down(): Promise { + // not implemented + } +} diff --git a/server/src/queries/asset.repository.sql b/server/src/queries/asset.repository.sql index 98edc8da1d..e7f5b558b0 100644 --- a/server/src/queries/asset.repository.sql +++ b/server/src/queries/asset.repository.sql @@ -183,9 +183,6 @@ SELECT "AssetEntity__AssetEntity_exifInfo"."bitsPerSample" AS "AssetEntity__AssetEntity_exifInfo_bitsPerSample", "AssetEntity__AssetEntity_exifInfo"."rating" AS "AssetEntity__AssetEntity_exifInfo_rating", "AssetEntity__AssetEntity_exifInfo"."fps" AS "AssetEntity__AssetEntity_exifInfo_fps", - "AssetEntity__AssetEntity_smartInfo"."assetId" AS "AssetEntity__AssetEntity_smartInfo_assetId", - "AssetEntity__AssetEntity_smartInfo"."tags" AS "AssetEntity__AssetEntity_smartInfo_tags", - "AssetEntity__AssetEntity_smartInfo"."objects" AS "AssetEntity__AssetEntity_smartInfo_objects", "AssetEntity__AssetEntity_tags"."id" AS "AssetEntity__AssetEntity_tags_id", "AssetEntity__AssetEntity_tags"."value" AS "AssetEntity__AssetEntity_tags_value", "AssetEntity__AssetEntity_tags"."createdAt" AS "AssetEntity__AssetEntity_tags_createdAt", @@ -252,7 +249,6 @@ SELECT FROM "assets" "AssetEntity" LEFT JOIN "exif" "AssetEntity__AssetEntity_exifInfo" ON "AssetEntity__AssetEntity_exifInfo"."assetId" = "AssetEntity"."id" - LEFT JOIN "smart_info" "AssetEntity__AssetEntity_smartInfo" ON "AssetEntity__AssetEntity_smartInfo"."assetId" = "AssetEntity"."id" LEFT JOIN "tag_asset" "AssetEntity_AssetEntity__AssetEntity_tags" ON "AssetEntity_AssetEntity__AssetEntity_tags"."assetsId" = "AssetEntity"."id" LEFT JOIN "tags" "AssetEntity__AssetEntity_tags" ON "AssetEntity__AssetEntity_tags"."id" = "AssetEntity_AssetEntity__AssetEntity_tags"."tagsId" LEFT JOIN "asset_faces" "AssetEntity__AssetEntity_faces" ON "AssetEntity__AssetEntity_faces"."assetId" = "AssetEntity"."id" @@ -932,36 +928,6 @@ WHERE LIMIT 12 --- AssetRepository.getAssetIdByTag -WITH - "random_tags" AS ( - SELECT - unnest(tags) AS "tag" - FROM - "smart_info" "si" - GROUP BY - tag - HAVING - count(*) >= $1 - ) -SELECT DISTINCT - ON (unnest("si"."tags")) "asset"."id" AS "data", - unnest("si"."tags") AS "value" -FROM - "assets" "asset" - INNER JOIN "smart_info" "si" ON "asset"."id" = si."assetId" - INNER JOIN "random_tags" "t" ON "si"."tags" @> ARRAY[t.tag] -WHERE - ( - "asset"."isVisible" = true - AND "asset"."type" = $2 - AND "asset"."ownerId" IN ($3) - AND "asset"."isArchived" = $4 - ) - AND ("asset"."deletedAt" IS NULL) -LIMIT - 12 - -- AssetRepository.getAllForUserFullSync SELECT "asset"."id" AS "asset_id", diff --git a/server/src/repositories/asset.repository.ts b/server/src/repositories/asset.repository.ts index a50dd0f79c..ce7d257b40 100644 --- a/server/src/repositories/asset.repository.ts +++ b/server/src/repositories/asset.repository.ts @@ -5,7 +5,6 @@ import { AssetFileEntity } from 'src/entities/asset-files.entity'; import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity'; import { AssetEntity } from 'src/entities/asset.entity'; import { ExifEntity } from 'src/entities/exif.entity'; -import { SmartInfoEntity } from 'src/entities/smart-info.entity'; import { AssetFileType, AssetOrder, AssetStatus, AssetType, PaginationMode } from 'src/enum'; import { AssetBuilderOptions, @@ -60,7 +59,6 @@ export class AssetRepository implements IAssetRepository { @InjectRepository(AssetFileEntity) private fileRepository: Repository, @InjectRepository(ExifEntity) private exifRepository: Repository, @InjectRepository(AssetJobStatusEntity) private jobStatusRepository: Repository, - @InjectRepository(SmartInfoEntity) private smartInfoRepository: Repository, ) {} async upsertExif(exif: Partial): Promise { @@ -119,7 +117,6 @@ export class AssetRepository implements IAssetRepository { where: { id: In(ids) }, relations: { exifInfo: true, - smartInfo: true, tags: true, faces: { person: true, @@ -422,22 +419,6 @@ export class AssetRepository implements IAssetRepository { break; } - case WithoutProperty.OBJECT_TAGS: { - relations = { - smartInfo: true, - }; - where = { - jobStatus: { - previewAt: Not(IsNull()), - }, - isVisible: true, - smartInfo: { - tags: IsNull(), - }, - }; - break; - } - case WithoutProperty.FACES: { relations = { faces: true, @@ -457,23 +438,6 @@ export class AssetRepository implements IAssetRepository { break; } - case WithoutProperty.PERSON: { - relations = { - faces: true, - }; - where = { - jobStatus: { - previewAt: Not(IsNull()), - }, - isVisible: true, - faces: { - assetId: Not(IsNull()), - personId: IsNull(), - }, - }; - break; - } - case WithoutProperty.SIDECAR: { where = [ { sidecarPath: IsNull(), isVisible: true }, @@ -611,35 +575,6 @@ export class AssetRepository implements IAssetRepository { return { fieldName: 'exifInfo.city', items }; } - @GenerateSql({ params: [DummyValue.UUID, { minAssetsPerField: 5, maxFields: 12 }] }) - async getAssetIdByTag( - ownerId: string, - { minAssetsPerField, maxFields }: AssetExploreFieldOptions, - ): Promise> { - const cte = this.smartInfoRepository - .createQueryBuilder('si') - .select('unnest(tags)', 'tag') - .groupBy('tag') - .having('count(*) >= :minAssetsPerField', { minAssetsPerField }); - - const items = await this.getBuilder({ - userIds: [ownerId], - exifInfo: false, - assetType: AssetType.IMAGE, - isArchived: false, - }) - .select('unnest(si.tags)', 'value') - .addSelect('asset.id', 'data') - .distinctOn(['unnest(si.tags)']) - .innerJoin('smart_info', 'si', 'asset.id = si."assetId"') - .addCommonTableExpression(cte, 'random_tags') - .innerJoin('random_tags', 't', 'si.tags @> ARRAY[t.tag]') - .limit(maxFields) - .getRawMany(); - - return { fieldName: 'smartInfo.tags', items }; - } - private getBuilder(options: AssetBuilderOptions) { const builder = this.repository.createQueryBuilder('asset').where('asset.isVisible = true'); diff --git a/server/src/repositories/search.repository.ts b/server/src/repositories/search.repository.ts index b5969beecb..01b7773076 100644 --- a/server/src/repositories/search.repository.ts +++ b/server/src/repositories/search.repository.ts @@ -6,7 +6,6 @@ import { AssetFaceEntity } from 'src/entities/asset-face.entity'; import { AssetEntity } from 'src/entities/asset.entity'; import { ExifEntity } from 'src/entities/exif.entity'; import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity'; -import { SmartInfoEntity } from 'src/entities/smart-info.entity'; import { SmartSearchEntity } from 'src/entities/smart-search.entity'; import { AssetType, PaginationMode } from 'src/enum'; import { IConfigRepository } from 'src/interfaces/config.interface'; @@ -34,7 +33,6 @@ export class SearchRepository implements ISearchRepository { private assetsByCityQuery: string; constructor( - @InjectRepository(SmartInfoEntity) private repository: Repository, @InjectRepository(AssetEntity) private assetRepository: Repository, @InjectRepository(ExifEntity) private exifRepository: Repository, @InjectRepository(AssetFaceEntity) private assetFaceRepository: Repository, @@ -278,7 +276,7 @@ export class SearchRepository implements ISearchRepository { @GenerateSql({ params: [[DummyValue.UUID]] }) async getAssetsByCity(userIds: string[]): Promise { const parameters = [userIds, true, false, AssetType.IMAGE]; - const rawRes = await this.repository.query(this.assetsByCityQuery, parameters); + const rawRes = await this.assetRepository.query(this.assetsByCityQuery, parameters); const items: AssetEntity[] = []; for (const res of rawRes) { diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index e9f128194b..98d6ec00f6 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -94,7 +94,6 @@ export class AssetService extends BaseService { { exifInfo: true, sharedLinks: true, - smartInfo: true, tags: true, owner: true, faces: { @@ -162,7 +161,6 @@ export class AssetService extends BaseService { const asset = await this.assetRepository.getById(id, { exifInfo: true, owner: true, - smartInfo: true, tags: true, faces: { person: true, diff --git a/server/src/services/search.service.spec.ts b/server/src/services/search.service.spec.ts index e0b03f31ae..0f95d88083 100644 --- a/server/src/services/search.service.spec.ts +++ b/server/src/services/search.service.spec.ts @@ -47,14 +47,9 @@ describe(SearchService.name, () => { fieldName: 'exifInfo.city', items: [{ value: 'Paris', data: assetStub.image.id }], }); - assetMock.getAssetIdByTag.mockResolvedValue({ - fieldName: 'smartInfo.tags', - items: [{ value: 'train', data: assetStub.imageFrom2015.id }], - }); assetMock.getByIdsWithAllRelations.mockResolvedValue([assetStub.image, assetStub.imageFrom2015]); const expectedResponse = [ { fieldName: 'exifInfo.city', items: [{ value: 'Paris', data: mapAsset(assetStub.image) }] }, - { fieldName: 'smartInfo.tags', items: [{ value: 'train', data: mapAsset(assetStub.imageFrom2015) }] }, ]; const result = await sut.getExploreData(authStub.user1); diff --git a/server/src/services/search.service.ts b/server/src/services/search.service.ts index 03ffbe97db..04d3addb63 100644 --- a/server/src/services/search.service.ts +++ b/server/src/services/search.service.ts @@ -34,10 +34,8 @@ export class SearchService extends BaseService { async getExploreData(auth: AuthDto): Promise[]> { const options = { maxFields: 12, minAssetsPerField: 5 }; - const results = await Promise.all([ - this.assetRepository.getAssetIdByCity(auth.user.id, options), - this.assetRepository.getAssetIdByTag(auth.user.id, options), - ]); + const result = await this.assetRepository.getAssetIdByCity(auth.user.id, options); + const results = [result]; const assetIds = new Set(results.flatMap((field) => field.items.map((item) => item.data))); const assets = await this.assetRepository.getByIdsWithAllRelations([...assetIds]); const assetMap = new Map(assets.map((asset) => [asset.id, mapAsset(asset)])); diff --git a/server/src/utils/database.ts b/server/src/utils/database.ts index 55e4fcb0e5..ad2198b38c 100644 --- a/server/src/utils/database.ts +++ b/server/src/utils/database.ts @@ -90,7 +90,6 @@ export function searchAssetBuilder( isNotInAlbum, withFaces, withPeople, - withSmartInfo, personIds, withStacked, trashedAfter, @@ -123,10 +122,6 @@ export function searchAssetBuilder( builder.leftJoinAndSelect('faces.person', 'person'); } - if (withSmartInfo) { - builder.leftJoinAndSelect(`${builder.alias}.smartInfo`, 'smartInfo'); - } - if (personIds && personIds.length > 0) { const cte = builder .createQueryBuilder() diff --git a/server/test/fixtures/shared-link.stub.ts b/server/test/fixtures/shared-link.stub.ts index e446a6180b..a8b8e02d74 100644 --- a/server/test/fixtures/shared-link.stub.ts +++ b/server/test/fixtures/shared-link.stub.ts @@ -62,10 +62,6 @@ const assetResponse: AssetResponseDto = { updatedAt: today, isFavorite: false, isArchived: false, - smartInfo: { - tags: [], - objects: ['a', 'b', 'c'], - }, duration: '0:00:00.00000', exifInfo: assetInfo, livePhotoVideoId: null, @@ -205,12 +201,6 @@ export const sharedLinkStub = { isArchived: false, isExternal: false, isOffline: false, - smartInfo: { - assetId: 'id_1', - tags: [], - objects: ['a', 'b', 'c'], - asset: null as any, - }, files: [], thumbhash: null, encodedVideoPath: '', diff --git a/server/test/repositories/asset.repository.mock.ts b/server/test/repositories/asset.repository.mock.ts index 982273ff69..928a7956c5 100644 --- a/server/test/repositories/asset.repository.mock.ts +++ b/server/test/repositories/asset.repository.mock.ts @@ -33,7 +33,6 @@ export const newAssetRepositoryMock = (): Mocked => { getTimeBucket: vitest.fn(), getTimeBuckets: vitest.fn(), getAssetIdByCity: vitest.fn(), - getAssetIdByTag: vitest.fn(), getAllForUserFullSync: vitest.fn(), getChangedDeltaSync: vitest.fn(), getDuplicates: vitest.fn(), diff --git a/web/package-lock.json b/web/package-lock.json index d8eb0a791b..8cd702d7bd 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich-web", - "version": "1.120.0", + "version": "1.120.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich-web", - "version": "1.120.0", + "version": "1.120.1", "license": "GNU Affero General Public License version 3", "dependencies": { "@formatjs/icu-messageformat-parser": "^2.7.8", @@ -74,7 +74,7 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.120.0", + "version": "1.120.1", "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" diff --git a/web/package.json b/web/package.json index 6df4894102..b03379ee01 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "immich-web", - "version": "1.120.0", + "version": "1.120.1", "license": "GNU Affero General Public License version 3", "scripts": { "dev": "vite dev --host 0.0.0.0 --port 3000", diff --git a/web/src/routes/(user)/explore/+page.svelte b/web/src/routes/(user)/explore/+page.svelte index 18c9dffdf3..ebd2e96b5a 100644 --- a/web/src/routes/(user)/explore/+page.svelte +++ b/web/src/routes/(user)/explore/+page.svelte @@ -16,8 +16,6 @@ enum Field { CITY = 'exifInfo.city', - TAGS = 'smartInfo.tags', - OBJECTS = 'smartInfo.objects', } const getFieldItems = (items: SearchExploreResponseDto[], field: Field) => {