mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat (web/server) 360 degrees Web panoramas [attempt 2] (#3412)
* commit 1 (isPanorama: boolean) * working solution for projectiontypeenum * fix * format fix * fix * fix * fix * fix * enum projectiontype * working solution with exif * fix * reverted > * fix format * reverted auto-magic api.ts prettification * fix * reverted api.ts autogenerated * api ts regenerated * Update web/src/lib/components/assets/thumbnail/thumbnail.svelte Co-authored-by: Sergey Kondrikov <sergey.kondrikov@gmail.com> * Update web/src/lib/components/asset-viewer/asset-viewer.svelte Co-authored-by: Sergey Kondrikov <sergey.kondrikov@gmail.com> * exifProjectionType * Update server/src/microservices/processors/metadata-extraction.processor.ts Co-authored-by: Sergey Kondrikov <sergey.kondrikov@gmail.com> * projectionType?: string = ProjectionType.NONE; * not null * projectionType!: ProjectionType; * opeapi generator fix * fixes * fix * fix * generate api * asset.exifInifo?.projectionType * Update server/src/domain/asset/response-dto/exif-response.dto.ts Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> * Update server/src/microservices/processors/metadata-extraction.processor.ts Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> * enum -> varchar;projectiontypeenum->projectiontype * asset-viewer fixed prettiffier * @Column({}) single line * enum | string * make api * enum | string * enum | str fix * fix * chore: use string instead of enum * chore: open api * fix: checks --------- Co-authored-by: Sergey Kondrikov <sergey.kondrikov@gmail.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com> Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
		
							
								
								
									
										6
									
								
								cli/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								cli/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							@@ -1304,6 +1304,12 @@ export interface ExifResponseDto {
 | 
				
			|||||||
     * @memberof ExifResponseDto
 | 
					     * @memberof ExifResponseDto
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    'description'?: string | null;
 | 
					    'description'?: string | null;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     * @memberof ExifResponseDto
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    'projectionType'?: string | null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 
 | 
					 * 
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								mobile/openapi/doc/ExifResponseDto.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								mobile/openapi/doc/ExifResponseDto.md
									
									
									
										generated
									
									
									
								
							@@ -28,6 +28,7 @@ Name | Type | Description | Notes
 | 
				
			|||||||
**state** | **String** |  | [optional] 
 | 
					**state** | **String** |  | [optional] 
 | 
				
			||||||
**country** | **String** |  | [optional] 
 | 
					**country** | **String** |  | [optional] 
 | 
				
			||||||
**description** | **String** |  | [optional] 
 | 
					**description** | **String** |  | [optional] 
 | 
				
			||||||
 | 
					**projectionType** | **String** |  | [optional] 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
					[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								mobile/openapi/lib/model/exif_response_dto.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										17
									
								
								mobile/openapi/lib/model/exif_response_dto.dart
									
									
									
										generated
									
									
									
								
							@@ -33,6 +33,7 @@ class ExifResponseDto {
 | 
				
			|||||||
    this.state,
 | 
					    this.state,
 | 
				
			||||||
    this.country,
 | 
					    this.country,
 | 
				
			||||||
    this.description,
 | 
					    this.description,
 | 
				
			||||||
 | 
					    this.projectionType,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int? fileSizeInByte;
 | 
					  int? fileSizeInByte;
 | 
				
			||||||
@@ -75,6 +76,8 @@ class ExifResponseDto {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  String? description;
 | 
					  String? description;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String? projectionType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  bool operator ==(Object other) => identical(this, other) || other is ExifResponseDto &&
 | 
					  bool operator ==(Object other) => identical(this, other) || other is ExifResponseDto &&
 | 
				
			||||||
     other.fileSizeInByte == fileSizeInByte &&
 | 
					     other.fileSizeInByte == fileSizeInByte &&
 | 
				
			||||||
@@ -96,7 +99,8 @@ class ExifResponseDto {
 | 
				
			|||||||
     other.city == city &&
 | 
					     other.city == city &&
 | 
				
			||||||
     other.state == state &&
 | 
					     other.state == state &&
 | 
				
			||||||
     other.country == country &&
 | 
					     other.country == country &&
 | 
				
			||||||
     other.description == description;
 | 
					     other.description == description &&
 | 
				
			||||||
 | 
					     other.projectionType == projectionType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  int get hashCode =>
 | 
					  int get hashCode =>
 | 
				
			||||||
@@ -120,10 +124,11 @@ class ExifResponseDto {
 | 
				
			|||||||
    (city == null ? 0 : city!.hashCode) +
 | 
					    (city == null ? 0 : city!.hashCode) +
 | 
				
			||||||
    (state == null ? 0 : state!.hashCode) +
 | 
					    (state == null ? 0 : state!.hashCode) +
 | 
				
			||||||
    (country == null ? 0 : country!.hashCode) +
 | 
					    (country == null ? 0 : country!.hashCode) +
 | 
				
			||||||
    (description == null ? 0 : description!.hashCode);
 | 
					    (description == null ? 0 : description!.hashCode) +
 | 
				
			||||||
 | 
					    (projectionType == null ? 0 : projectionType!.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String toString() => 'ExifResponseDto[fileSizeInByte=$fileSizeInByte, make=$make, model=$model, exifImageWidth=$exifImageWidth, exifImageHeight=$exifImageHeight, orientation=$orientation, dateTimeOriginal=$dateTimeOriginal, modifyDate=$modifyDate, timeZone=$timeZone, lensModel=$lensModel, fNumber=$fNumber, focalLength=$focalLength, iso=$iso, exposureTime=$exposureTime, latitude=$latitude, longitude=$longitude, city=$city, state=$state, country=$country, description=$description]';
 | 
					  String toString() => 'ExifResponseDto[fileSizeInByte=$fileSizeInByte, make=$make, model=$model, exifImageWidth=$exifImageWidth, exifImageHeight=$exifImageHeight, orientation=$orientation, dateTimeOriginal=$dateTimeOriginal, modifyDate=$modifyDate, timeZone=$timeZone, lensModel=$lensModel, fNumber=$fNumber, focalLength=$focalLength, iso=$iso, exposureTime=$exposureTime, latitude=$latitude, longitude=$longitude, city=$city, state=$state, country=$country, description=$description, projectionType=$projectionType]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Map<String, dynamic> toJson() {
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
    final json = <String, dynamic>{};
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
@@ -227,6 +232,11 @@ class ExifResponseDto {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
    //  json[r'description'] = null;
 | 
					    //  json[r'description'] = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (this.projectionType != null) {
 | 
				
			||||||
 | 
					      json[r'projectionType'] = this.projectionType;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    //  json[r'projectionType'] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return json;
 | 
					    return json;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -272,6 +282,7 @@ class ExifResponseDto {
 | 
				
			|||||||
        state: mapValueOfType<String>(json, r'state'),
 | 
					        state: mapValueOfType<String>(json, r'state'),
 | 
				
			||||||
        country: mapValueOfType<String>(json, r'country'),
 | 
					        country: mapValueOfType<String>(json, r'country'),
 | 
				
			||||||
        description: mapValueOfType<String>(json, r'description'),
 | 
					        description: mapValueOfType<String>(json, r'description'),
 | 
				
			||||||
 | 
					        projectionType: mapValueOfType<String>(json, r'projectionType'),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								mobile/openapi/test/exif_response_dto_test.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								mobile/openapi/test/exif_response_dto_test.dart
									
									
									
										generated
									
									
									
								
							@@ -116,6 +116,11 @@ void main() {
 | 
				
			|||||||
      // TODO
 | 
					      // TODO
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // String projectionType
 | 
				
			||||||
 | 
					    test('to test the property `projectionType`', () async {
 | 
				
			||||||
 | 
					      // TODO
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5553,6 +5553,11 @@
 | 
				
			|||||||
            "type": "string",
 | 
					            "type": "string",
 | 
				
			||||||
            "nullable": true,
 | 
					            "nullable": true,
 | 
				
			||||||
            "default": null
 | 
					            "default": null
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "projectionType": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "nullable": true,
 | 
				
			||||||
 | 
					            "default": null
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										75
									
								
								server/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										75
									
								
								server/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -28,7 +28,7 @@
 | 
				
			|||||||
        "class-transformer": "^0.5.1",
 | 
					        "class-transformer": "^0.5.1",
 | 
				
			||||||
        "class-validator": "^0.14.0",
 | 
					        "class-validator": "^0.14.0",
 | 
				
			||||||
        "cookie-parser": "^1.4.6",
 | 
					        "cookie-parser": "^1.4.6",
 | 
				
			||||||
        "exiftool-vendored": "^19.0.0",
 | 
					        "exiftool-vendored": "^22.0.0",
 | 
				
			||||||
        "exiftool-vendored.pl": "^12.54.0",
 | 
					        "exiftool-vendored.pl": "^12.54.0",
 | 
				
			||||||
        "fluent-ffmpeg": "^2.1.2",
 | 
					        "fluent-ffmpeg": "^2.1.2",
 | 
				
			||||||
        "handlebars": "^4.7.7",
 | 
					        "handlebars": "^4.7.7",
 | 
				
			||||||
@@ -4064,9 +4064,9 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/batch-cluster": {
 | 
					    "node_modules/batch-cluster": {
 | 
				
			||||||
      "version": "11.0.0",
 | 
					      "version": "12.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/batch-cluster/-/batch-cluster-11.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/batch-cluster/-/batch-cluster-12.1.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-8iwqa+rKTaakOHkqdcXDT5L5117pa+FoP8/yAKpNdL44ZnC4V2NEA/sIg0ZO0O9NkpdjLk0A3efRFM5nVizqHw==",
 | 
					      "integrity": "sha512-whGyJU4tr7kyg2USByu0/51mML5HsLAeNz5s03kMDYZNsQsGgDJgI47RdY3r7MciCjPkTaTD5O4eOVqOfEO7pg==",
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=14"
 | 
					        "node": ">=14"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -5976,25 +5976,25 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/exiftool-vendored": {
 | 
					    "node_modules/exiftool-vendored": {
 | 
				
			||||||
      "version": "19.0.0",
 | 
					      "version": "22.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-19.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-22.0.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-Zes7TZrYWxts92mbF2Gs3drtWZucm4qsaeYaE6A+OOqmeD9UGaGisqIbyh9MilJrLi+ZHzWEJZtDj37QFf6xsA==",
 | 
					      "integrity": "sha512-gBOQ4C2GLjxKPDPRuUbMOz91mG6IFA22L+Z/IQzFotFu20vc7YroqHALf/ophCbANA5sNSArbVDPijP7n/20Jg==",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@photostructure/tz-lookup": "^7.0.0",
 | 
					        "@photostructure/tz-lookup": "^7.0.0",
 | 
				
			||||||
        "@types/luxon": "^3.2.0",
 | 
					        "@types/luxon": "^3.3.0",
 | 
				
			||||||
        "batch-cluster": "^11.0.0",
 | 
					        "batch-cluster": "^12.1.0",
 | 
				
			||||||
        "he": "^1.2.0",
 | 
					        "he": "^1.2.0",
 | 
				
			||||||
        "luxon": "^3.2.1"
 | 
					        "luxon": "^3.3.0"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "optionalDependencies": {
 | 
					      "optionalDependencies": {
 | 
				
			||||||
        "exiftool-vendored.exe": "12.54.0",
 | 
					        "exiftool-vendored.exe": "12.62.0",
 | 
				
			||||||
        "exiftool-vendored.pl": "12.54.0"
 | 
					        "exiftool-vendored.pl": "12.62.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/exiftool-vendored.exe": {
 | 
					    "node_modules/exiftool-vendored.exe": {
 | 
				
			||||||
      "version": "12.54.0",
 | 
					      "version": "12.62.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.54.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.62.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-Dc4W6e0NtQfYuJIYK4piHfDJnd2jvA04e0aaq9R3Q1oO34KC5e+L1D2C7lFuZXqPQLYC1x3GYc/GVv5e+SkkrQ==",
 | 
					      "integrity": "sha512-xNFkvmjwnMg6ivtmkc67w1qD23fIy06nRpMpGuBpTwTqAVatHV+vk7T75zyvLoXRRpd1rKID9XAVLGJCE/iiMQ==",
 | 
				
			||||||
      "optional": true,
 | 
					      "optional": true,
 | 
				
			||||||
      "os": [
 | 
					      "os": [
 | 
				
			||||||
        "win32"
 | 
					        "win32"
 | 
				
			||||||
@@ -6008,15 +6008,6 @@
 | 
				
			|||||||
        "!win32"
 | 
					        "!win32"
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/exiftool-vendored/node_modules/exiftool-vendored.pl": {
 | 
					 | 
				
			||||||
      "version": "12.54.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.54.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-RBBowsYcM6EvbWoBkg2dOqHpH3WIzN7bIzHc+o+LquqCTo3doZwECClD/6PNHVSMQsl2Z0fEf75sNq2msooMSg==",
 | 
					 | 
				
			||||||
      "optional": true,
 | 
					 | 
				
			||||||
      "os": [
 | 
					 | 
				
			||||||
        "!win32"
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "node_modules/exit": {
 | 
					    "node_modules/exit": {
 | 
				
			||||||
      "version": "0.1.2",
 | 
					      "version": "0.1.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
 | 
				
			||||||
@@ -15584,9 +15575,9 @@
 | 
				
			|||||||
      "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
 | 
					      "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "batch-cluster": {
 | 
					    "batch-cluster": {
 | 
				
			||||||
      "version": "11.0.0",
 | 
					      "version": "12.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/batch-cluster/-/batch-cluster-11.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/batch-cluster/-/batch-cluster-12.1.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-8iwqa+rKTaakOHkqdcXDT5L5117pa+FoP8/yAKpNdL44ZnC4V2NEA/sIg0ZO0O9NkpdjLk0A3efRFM5nVizqHw=="
 | 
					      "integrity": "sha512-whGyJU4tr7kyg2USByu0/51mML5HsLAeNz5s03kMDYZNsQsGgDJgI47RdY3r7MciCjPkTaTD5O4eOVqOfEO7pg=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "bcrypt": {
 | 
					    "bcrypt": {
 | 
				
			||||||
      "version": "5.1.0",
 | 
					      "version": "5.1.0",
 | 
				
			||||||
@@ -17011,31 +17002,23 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "exiftool-vendored": {
 | 
					    "exiftool-vendored": {
 | 
				
			||||||
      "version": "19.0.0",
 | 
					      "version": "22.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-19.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-22.0.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-Zes7TZrYWxts92mbF2Gs3drtWZucm4qsaeYaE6A+OOqmeD9UGaGisqIbyh9MilJrLi+ZHzWEJZtDj37QFf6xsA==",
 | 
					      "integrity": "sha512-gBOQ4C2GLjxKPDPRuUbMOz91mG6IFA22L+Z/IQzFotFu20vc7YroqHALf/ophCbANA5sNSArbVDPijP7n/20Jg==",
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "@photostructure/tz-lookup": "^7.0.0",
 | 
					        "@photostructure/tz-lookup": "^7.0.0",
 | 
				
			||||||
        "@types/luxon": "^3.2.0",
 | 
					        "@types/luxon": "^3.3.0",
 | 
				
			||||||
        "batch-cluster": "^11.0.0",
 | 
					        "batch-cluster": "^12.1.0",
 | 
				
			||||||
        "exiftool-vendored.exe": "12.54.0",
 | 
					        "exiftool-vendored.exe": "12.62.0",
 | 
				
			||||||
        "exiftool-vendored.pl": "12.54.0",
 | 
					        "exiftool-vendored.pl": "12.62.0",
 | 
				
			||||||
        "he": "^1.2.0",
 | 
					        "he": "^1.2.0",
 | 
				
			||||||
        "luxon": "^3.2.1"
 | 
					        "luxon": "^3.3.0"
 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "exiftool-vendored.pl": {
 | 
					 | 
				
			||||||
          "version": "12.54.0",
 | 
					 | 
				
			||||||
          "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.54.0.tgz",
 | 
					 | 
				
			||||||
          "integrity": "sha512-RBBowsYcM6EvbWoBkg2dOqHpH3WIzN7bIzHc+o+LquqCTo3doZwECClD/6PNHVSMQsl2Z0fEf75sNq2msooMSg==",
 | 
					 | 
				
			||||||
          "optional": true
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "exiftool-vendored.exe": {
 | 
					    "exiftool-vendored.exe": {
 | 
				
			||||||
      "version": "12.54.0",
 | 
					      "version": "12.62.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.54.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.62.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-Dc4W6e0NtQfYuJIYK4piHfDJnd2jvA04e0aaq9R3Q1oO34KC5e+L1D2C7lFuZXqPQLYC1x3GYc/GVv5e+SkkrQ==",
 | 
					      "integrity": "sha512-xNFkvmjwnMg6ivtmkc67w1qD23fIy06nRpMpGuBpTwTqAVatHV+vk7T75zyvLoXRRpd1rKID9XAVLGJCE/iiMQ==",
 | 
				
			||||||
      "optional": true
 | 
					      "optional": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "exiftool-vendored.pl": {
 | 
					    "exiftool-vendored.pl": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@
 | 
				
			|||||||
    "class-transformer": "^0.5.1",
 | 
					    "class-transformer": "^0.5.1",
 | 
				
			||||||
    "class-validator": "^0.14.0",
 | 
					    "class-validator": "^0.14.0",
 | 
				
			||||||
    "cookie-parser": "^1.4.6",
 | 
					    "cookie-parser": "^1.4.6",
 | 
				
			||||||
    "exiftool-vendored": "^19.0.0",
 | 
					    "exiftool-vendored": "^22.0.0",
 | 
				
			||||||
    "exiftool-vendored.pl": "^12.54.0",
 | 
					    "exiftool-vendored.pl": "^12.54.0",
 | 
				
			||||||
    "fluent-ffmpeg": "^2.1.2",
 | 
					    "fluent-ffmpeg": "^2.1.2",
 | 
				
			||||||
    "handlebars": "^4.7.7",
 | 
					    "handlebars": "^4.7.7",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ export class ExifResponseDto {
 | 
				
			|||||||
  state?: string | null = null;
 | 
					  state?: string | null = null;
 | 
				
			||||||
  country?: string | null = null;
 | 
					  country?: string | null = null;
 | 
				
			||||||
  description?: string | null = null;
 | 
					  description?: string | null = null;
 | 
				
			||||||
 | 
					  projectionType?: string | null = null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function mapExif(entity: ExifEntity): ExifResponseDto {
 | 
					export function mapExif(entity: ExifEntity): ExifResponseDto {
 | 
				
			||||||
@@ -48,5 +49,6 @@ export function mapExif(entity: ExifEntity): ExifResponseDto {
 | 
				
			|||||||
    state: entity.state,
 | 
					    state: entity.state,
 | 
				
			||||||
    country: entity.country,
 | 
					    country: entity.country,
 | 
				
			||||||
    description: entity.description,
 | 
					    description: entity.description,
 | 
				
			||||||
 | 
					    projectionType: entity.projectionType,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,9 @@ export class ExifEntity {
 | 
				
			|||||||
  @Column({ type: 'float', nullable: true })
 | 
					  @Column({ type: 'float', nullable: true })
 | 
				
			||||||
  longitude!: number | null;
 | 
					  longitude!: number | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Column({ type: 'varchar', nullable: true })
 | 
				
			||||||
 | 
					  projectionType!: string | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Column({ type: 'varchar', nullable: true })
 | 
					  @Column({ type: 'varchar', nullable: true })
 | 
				
			||||||
  city!: string | null;
 | 
					  city!: string | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								server/src/infra/migrations/1690469489288-Panoramas.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								server/src/infra/migrations/1690469489288-Panoramas.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					import { MigrationInterface, QueryRunner } from 'typeorm';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Panoramas1690217088596 implements MigrationInterface {
 | 
				
			||||||
 | 
					  name = 'Panoramas1690217088596';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public async up(queryRunner: QueryRunner): Promise<void> {
 | 
				
			||||||
 | 
					    await queryRunner.query(`ALTER TABLE "exif" ADD "projectionType" character varying`);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public async down(queryRunner: QueryRunner): Promise<void> {
 | 
				
			||||||
 | 
					    await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "projectionType"`);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -336,6 +336,12 @@ export class MetadataExtractionProcessor {
 | 
				
			|||||||
        await this.extractEmbeddedVideo(asset, offset, null, fileCreatedAt);
 | 
					        await this.extractEmbeddedVideo(asset, offset, null, fileCreatedAt);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const projectionType = getExifProperty('ProjectionType');
 | 
				
			||||||
 | 
					    if (projectionType) {
 | 
				
			||||||
 | 
					      newExif.projectionType = String(projectionType).toUpperCase();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    newExif.livePhotoCID = getExifProperty('MediaGroupUUID');
 | 
					    newExif.livePhotoCID = getExifProperty('MediaGroupUUID');
 | 
				
			||||||
    if (newExif.livePhotoCID && !asset.livePhotoVideoId) {
 | 
					    if (newExif.livePhotoCID && !asset.livePhotoVideoId) {
 | 
				
			||||||
      const motionAsset = await this.assetRepository.findLivePhotoMatch({
 | 
					      const motionAsset = await this.assetRepository.findLivePhotoMatch({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -625,6 +625,7 @@ const assetInfo: ExifResponseDto = {
 | 
				
			|||||||
  state: 'state',
 | 
					  state: 'state',
 | 
				
			||||||
  country: 'country',
 | 
					  country: 'country',
 | 
				
			||||||
  description: 'description',
 | 
					  description: 'description',
 | 
				
			||||||
 | 
					  projectionType: null,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const assetResponse: AssetResponseDto = {
 | 
					const assetResponse: AssetResponseDto = {
 | 
				
			||||||
@@ -882,6 +883,7 @@ export const sharedLinkStub = {
 | 
				
			|||||||
          livePhotoVideoId: null,
 | 
					          livePhotoVideoId: null,
 | 
				
			||||||
          originalFileName: 'asset_1.jpeg',
 | 
					          originalFileName: 'asset_1.jpeg',
 | 
				
			||||||
          exifInfo: {
 | 
					          exifInfo: {
 | 
				
			||||||
 | 
					            projectionType: null,
 | 
				
			||||||
            livePhotoCID: null,
 | 
					            livePhotoCID: null,
 | 
				
			||||||
            assetId: 'id_1',
 | 
					            assetId: 'id_1',
 | 
				
			||||||
            description: 'description',
 | 
					            description: 'description',
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										103
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										103
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -8,6 +8,7 @@
 | 
				
			|||||||
      "name": "immich-web",
 | 
					      "name": "immich-web",
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@egjs/svelte-view360": "^4.0.0-beta.7",
 | 
				
			||||||
        "@zoom-image/svelte": "^0.1.8",
 | 
					        "@zoom-image/svelte": "^0.1.8",
 | 
				
			||||||
        "axios": "^0.27.2",
 | 
					        "axios": "^0.27.2",
 | 
				
			||||||
        "buffer": "^6.0.3",
 | 
					        "buffer": "^6.0.3",
 | 
				
			||||||
@@ -1840,6 +1841,47 @@
 | 
				
			|||||||
      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
 | 
					      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@cfcs/core": {
 | 
				
			||||||
 | 
					      "version": "0.0.24",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@cfcs/core/-/core-0.0.24.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-feB38qu+eDk0Pggh/yR7gjaNmvUYA2uCxHP3Pz2MLE4LZ/9jPdtu8bzCSI47yTEhWyZCF5Pk698hdz8IN2mTjA==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@egjs/component": "^3.0.4"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@egjs/component": {
 | 
				
			||||||
 | 
					      "version": "3.0.4",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@egjs/component/-/component-3.0.4.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-sXA7bGbIeLF2OAw/vpka66c6QBBUPcA4UUhR4WGJfnp2XWdiI8QrnJGJMr/UxpE/xnevX9tN3jvNPlW8WkHl3g=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@egjs/imready": {
 | 
				
			||||||
 | 
					      "version": "1.4.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@egjs/imready/-/imready-1.4.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-JIOBs4lB7FYdsKi5uvz2j3SObX8eShtZjtqlOH41tm185aJOQZwiKBK8+V4MxzG4X6DqVhpdN8UcuVwBbElfsg==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@cfcs/core": "^0.0.24",
 | 
				
			||||||
 | 
					        "@egjs/component": "^3.0.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@egjs/svelte-view360": {
 | 
				
			||||||
 | 
					      "version": "4.0.0-beta.7",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@egjs/svelte-view360/-/svelte-view360-4.0.0-beta.7.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-qFNbLNME8H7QU2lg8SCKUTPoBXVdBcM5m8zmlDRE72esCTguDzUq2szXD7L1JWcb2lYPTFl3HVp/sZlcQ/1HpQ==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@egjs/view360": "4.0.0-beta.7"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@egjs/view360": {
 | 
				
			||||||
 | 
					      "version": "4.0.0-beta.7",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@egjs/view360/-/view360-4.0.0-beta.7.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-prVTTxuQ1/k59NM7G0tm58k2vPHGoaExoFr5E7MoJaSGF56Otj4okQHAxxosXH87aQLN0feZMtBlsKz0b/7zEw==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@egjs/component": "^3.0.2",
 | 
				
			||||||
 | 
					        "@egjs/imready": "^1.3.0",
 | 
				
			||||||
 | 
					        "@types/webxr": "^0.5.1",
 | 
				
			||||||
 | 
					        "gl-matrix": "^3.4.3"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@esbuild/android-arm": {
 | 
					    "node_modules/@esbuild/android-arm": {
 | 
				
			||||||
      "version": "0.17.19",
 | 
					      "version": "0.17.19",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
 | 
				
			||||||
@@ -3821,6 +3863,11 @@
 | 
				
			|||||||
      "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
 | 
					      "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@types/webxr": {
 | 
				
			||||||
 | 
					      "version": "0.5.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-szL74BnIcok9m7QwYtVmQ+EdIKwbjPANudfuvDrAF8Cljg9MKUlIoc1w5tjj9PMpeSH3U1Xnx//czQybJ0EfSw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@types/yargs": {
 | 
					    "node_modules/@types/yargs": {
 | 
				
			||||||
      "version": "17.0.22",
 | 
					      "version": "17.0.22",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz",
 | 
				
			||||||
@@ -6290,6 +6337,11 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
					        "url": "https://github.com/sponsors/sindresorhus"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/gl-matrix": {
 | 
				
			||||||
 | 
					      "version": "3.4.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/glob": {
 | 
					    "node_modules/glob": {
 | 
				
			||||||
      "version": "8.1.0",
 | 
					      "version": "8.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
 | 
				
			||||||
@@ -13334,6 +13386,47 @@
 | 
				
			|||||||
      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
 | 
					      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@cfcs/core": {
 | 
				
			||||||
 | 
					      "version": "0.0.24",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@cfcs/core/-/core-0.0.24.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-feB38qu+eDk0Pggh/yR7gjaNmvUYA2uCxHP3Pz2MLE4LZ/9jPdtu8bzCSI47yTEhWyZCF5Pk698hdz8IN2mTjA==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@egjs/component": "^3.0.4"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@egjs/component": {
 | 
				
			||||||
 | 
					      "version": "3.0.4",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@egjs/component/-/component-3.0.4.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-sXA7bGbIeLF2OAw/vpka66c6QBBUPcA4UUhR4WGJfnp2XWdiI8QrnJGJMr/UxpE/xnevX9tN3jvNPlW8WkHl3g=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@egjs/imready": {
 | 
				
			||||||
 | 
					      "version": "1.4.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@egjs/imready/-/imready-1.4.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-JIOBs4lB7FYdsKi5uvz2j3SObX8eShtZjtqlOH41tm185aJOQZwiKBK8+V4MxzG4X6DqVhpdN8UcuVwBbElfsg==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@cfcs/core": "^0.0.24",
 | 
				
			||||||
 | 
					        "@egjs/component": "^3.0.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@egjs/svelte-view360": {
 | 
				
			||||||
 | 
					      "version": "4.0.0-beta.7",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@egjs/svelte-view360/-/svelte-view360-4.0.0-beta.7.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-qFNbLNME8H7QU2lg8SCKUTPoBXVdBcM5m8zmlDRE72esCTguDzUq2szXD7L1JWcb2lYPTFl3HVp/sZlcQ/1HpQ==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@egjs/view360": "4.0.0-beta.7"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@egjs/view360": {
 | 
				
			||||||
 | 
					      "version": "4.0.0-beta.7",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@egjs/view360/-/view360-4.0.0-beta.7.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-prVTTxuQ1/k59NM7G0tm58k2vPHGoaExoFr5E7MoJaSGF56Otj4okQHAxxosXH87aQLN0feZMtBlsKz0b/7zEw==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@egjs/component": "^3.0.2",
 | 
				
			||||||
 | 
					        "@egjs/imready": "^1.3.0",
 | 
				
			||||||
 | 
					        "@types/webxr": "^0.5.1",
 | 
				
			||||||
 | 
					        "gl-matrix": "^3.4.3"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@esbuild/android-arm": {
 | 
					    "@esbuild/android-arm": {
 | 
				
			||||||
      "version": "0.17.19",
 | 
					      "version": "0.17.19",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
 | 
				
			||||||
@@ -14748,6 +14841,11 @@
 | 
				
			|||||||
      "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
 | 
					      "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/webxr": {
 | 
				
			||||||
 | 
					      "version": "0.5.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-szL74BnIcok9m7QwYtVmQ+EdIKwbjPANudfuvDrAF8Cljg9MKUlIoc1w5tjj9PMpeSH3U1Xnx//czQybJ0EfSw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@types/yargs": {
 | 
					    "@types/yargs": {
 | 
				
			||||||
      "version": "17.0.22",
 | 
					      "version": "17.0.22",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz",
 | 
				
			||||||
@@ -16510,6 +16608,11 @@
 | 
				
			|||||||
      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
 | 
					      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "gl-matrix": {
 | 
				
			||||||
 | 
					      "version": "3.4.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "glob": {
 | 
					    "glob": {
 | 
				
			||||||
      "version": "8.1.0",
 | 
					      "version": "8.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,7 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "type": "module",
 | 
					  "type": "module",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@egjs/svelte-view360": "^4.0.0-beta.7",
 | 
				
			||||||
    "@zoom-image/svelte": "^0.1.8",
 | 
					    "@zoom-image/svelte": "^0.1.8",
 | 
				
			||||||
    "axios": "^0.27.2",
 | 
					    "axios": "^0.27.2",
 | 
				
			||||||
    "buffer": "^6.0.3",
 | 
					    "buffer": "^6.0.3",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							@@ -1304,6 +1304,12 @@ export interface ExifResponseDto {
 | 
				
			|||||||
     * @memberof ExifResponseDto
 | 
					     * @memberof ExifResponseDto
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    'description'?: string | null;
 | 
					    'description'?: string | null;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     * @memberof ExifResponseDto
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    'projectionType'?: string | null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 
 | 
					 * 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,8 @@
 | 
				
			|||||||
  import DetailPanel from './detail-panel.svelte';
 | 
					  import DetailPanel from './detail-panel.svelte';
 | 
				
			||||||
  import PhotoViewer from './photo-viewer.svelte';
 | 
					  import PhotoViewer from './photo-viewer.svelte';
 | 
				
			||||||
  import VideoViewer from './video-viewer.svelte';
 | 
					  import VideoViewer from './video-viewer.svelte';
 | 
				
			||||||
 | 
					  import PanoramaViewer from './panorama-viewer.svelte';
 | 
				
			||||||
 | 
					  import { ProjectionType } from '$lib/constants';
 | 
				
			||||||
  import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
 | 
					  import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
 | 
				
			||||||
  import ProfileImageCropper from '../shared-components/profile-image-cropper.svelte';
 | 
					  import ProfileImageCropper from '../shared-components/profile-image-cropper.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -293,6 +295,8 @@
 | 
				
			|||||||
            on:close={closeViewer}
 | 
					            on:close={closeViewer}
 | 
				
			||||||
            on:onVideoEnded={() => (shouldPlayMotionPhoto = false)}
 | 
					            on:onVideoEnded={() => (shouldPlayMotionPhoto = false)}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
					        {:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR}
 | 
				
			||||||
 | 
					          <PanoramaViewer {publicSharedKey} {asset} />
 | 
				
			||||||
        {:else}
 | 
					        {:else}
 | 
				
			||||||
          <PhotoViewer {publicSharedKey} {asset} on:close={closeViewer} />
 | 
					          <PhotoViewer {publicSharedKey} {asset} on:close={closeViewer} />
 | 
				
			||||||
        {/if}
 | 
					        {/if}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								web/src/lib/components/asset-viewer/panorama-viewer.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								web/src/lib/components/asset-viewer/panorama-viewer.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					.view360-container {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  touch-action: pan-y;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.view360-canvas {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  -ms-user-select: none;
 | 
				
			||||||
 | 
					  user-select: none;
 | 
				
			||||||
 | 
					  -webkit-user-drag: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								web/src/lib/components/asset-viewer/panorama-viewer.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								web/src/lib/components/asset-viewer/panorama-viewer.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import { fade } from 'svelte/transition';
 | 
				
			||||||
 | 
					  import LoadingSpinner from '../shared-components/loading-spinner.svelte';
 | 
				
			||||||
 | 
					  import { api, AssetResponseDto } from '@api';
 | 
				
			||||||
 | 
					  import View360, { EquirectProjection } from '@egjs/svelte-view360';
 | 
				
			||||||
 | 
					  import './panorama-viewer.css';
 | 
				
			||||||
 | 
					  export let asset: AssetResponseDto;
 | 
				
			||||||
 | 
					  export let publicSharedKey = '';
 | 
				
			||||||
 | 
					  let dataUrl = '';
 | 
				
			||||||
 | 
					  let errorMessage = '';
 | 
				
			||||||
 | 
					  const loadAssetData = async () => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await api.assetApi.serveFile(
 | 
				
			||||||
 | 
					        { id: asset.id, isThumb: false, isWeb: false, key: publicSharedKey },
 | 
				
			||||||
 | 
					        { responseType: 'blob' },
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      if (data instanceof Blob) {
 | 
				
			||||||
 | 
					        dataUrl = URL.createObjectURL(data);
 | 
				
			||||||
 | 
					        return dataUrl;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        throw new Error('Invalid data format');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      errorMessage = 'Failed to load asset';
 | 
				
			||||||
 | 
					      return '';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div transition:fade={{ duration: 150 }} class="flex h-full select-none place-content-center place-items-center">
 | 
				
			||||||
 | 
					  {#await loadAssetData()}
 | 
				
			||||||
 | 
					    <LoadingSpinner />
 | 
				
			||||||
 | 
					  {:then assetData}
 | 
				
			||||||
 | 
					    {#if assetData}
 | 
				
			||||||
 | 
					      <View360 autoResize={true} initialZoom={0.5} projection={new EquirectProjection({ src: assetData })} />
 | 
				
			||||||
 | 
					    {:else}
 | 
				
			||||||
 | 
					      <p>{errorMessage}</p>
 | 
				
			||||||
 | 
					    {/if}
 | 
				
			||||||
 | 
					  {/await}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import { ProjectionType } from '$lib/constants';
 | 
				
			||||||
  import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte';
 | 
					  import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte';
 | 
				
			||||||
  import { timeToSeconds } from '$lib/utils/time-to-seconds';
 | 
					  import { timeToSeconds } from '$lib/utils/time-to-seconds';
 | 
				
			||||||
  import { api, AssetResponseDto, AssetTypeEnum, ThumbnailFormat } from '@api';
 | 
					  import { api, AssetResponseDto, AssetTypeEnum, ThumbnailFormat } from '@api';
 | 
				
			||||||
@@ -12,6 +13,7 @@
 | 
				
			|||||||
  import { fade } from 'svelte/transition';
 | 
					  import { fade } from 'svelte/transition';
 | 
				
			||||||
  import ImageThumbnail from './image-thumbnail.svelte';
 | 
					  import ImageThumbnail from './image-thumbnail.svelte';
 | 
				
			||||||
  import VideoThumbnail from './video-thumbnail.svelte';
 | 
					  import VideoThumbnail from './video-thumbnail.svelte';
 | 
				
			||||||
 | 
					  import Rotate360Icon from 'svelte-material-icons/Rotate360.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const dispatch = createEventDispatcher();
 | 
					  const dispatch = createEventDispatcher();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,6 +126,14 @@
 | 
				
			|||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        {/if}
 | 
					        {/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {#if asset.type === AssetTypeEnum.Image && asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR}
 | 
				
			||||||
 | 
					          <div class="absolute right-0 top-0 z-20 flex place-items-center gap-1 text-xs font-medium text-white">
 | 
				
			||||||
 | 
					            <span class="pr-2 pt-2">
 | 
				
			||||||
 | 
					              <Rotate360Icon size="24" />
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        {/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {#if asset.resized}
 | 
					        {#if asset.resized}
 | 
				
			||||||
          <ImageThumbnail
 | 
					          <ImageThumbnail
 | 
				
			||||||
            url={api.getAssetThumbnailUrl(asset.id, format, publicSharedKey)}
 | 
					            url={api.getAssetThumbnailUrl(asset.id, format, publicSharedKey)}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,3 +25,14 @@ export enum AppRoute {
 | 
				
			|||||||
  AUTH_REGISTER = '/auth/register',
 | 
					  AUTH_REGISTER = '/auth/register',
 | 
				
			||||||
  AUTH_CHANGE_PASSWORD = '/auth/change-password',
 | 
					  AUTH_CHANGE_PASSWORD = '/auth/change-password',
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum ProjectionType {
 | 
				
			||||||
 | 
					  EQUIRECTANGULAR = 'EQUIRECTANGULAR',
 | 
				
			||||||
 | 
					  CUBEMAP = 'CUBEMAP',
 | 
				
			||||||
 | 
					  CUBESTRIP = 'CUBESTRIP',
 | 
				
			||||||
 | 
					  EQUIRECTANGULAR_STEREO = 'EQUIRECTANGULAR_STEREO',
 | 
				
			||||||
 | 
					  CUBEMAP_STEREO = 'CUBEMAP_STEREO',
 | 
				
			||||||
 | 
					  CUBESTRIP_STEREO = 'CUBESTRIP_STEREO',
 | 
				
			||||||
 | 
					  CYLINDER = 'CYLINDER',
 | 
				
			||||||
 | 
					  NONE = 'NONE',
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user