save value
This commit is contained in:
parent
089fa7a550
commit
0309bba7dd
16 changed files with 161 additions and 14 deletions
12
cli/src/api/open-api/api.ts
generated
12
cli/src/api/open-api/api.ts
generated
|
@ -483,6 +483,12 @@ export interface AssetBulkUpdateDto {
|
|||
* @memberof AssetBulkUpdateDto
|
||||
*/
|
||||
'longitude'?: number;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof AssetBulkUpdateDto
|
||||
*/
|
||||
'orientation'?: number;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
|
@ -4191,6 +4197,12 @@ export interface UpdateAssetDto {
|
|||
* @memberof UpdateAssetDto
|
||||
*/
|
||||
'longitude'?: number;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof UpdateAssetDto
|
||||
*/
|
||||
'orientation'?: number;
|
||||
}
|
||||
/**
|
||||
*
|
||||
|
|
1
mobile/openapi/doc/AssetBulkUpdateDto.md
generated
1
mobile/openapi/doc/AssetBulkUpdateDto.md
generated
|
@ -14,6 +14,7 @@ Name | Type | Description | Notes
|
|||
**isFavorite** | **bool** | | [optional]
|
||||
**latitude** | **num** | | [optional]
|
||||
**longitude** | **num** | | [optional]
|
||||
**orientation** | **num** | | [optional]
|
||||
**removeParent** | **bool** | | [optional]
|
||||
**stackParentId** | **String** | | [optional]
|
||||
|
||||
|
|
1
mobile/openapi/doc/UpdateAssetDto.md
generated
1
mobile/openapi/doc/UpdateAssetDto.md
generated
|
@ -14,6 +14,7 @@ Name | Type | Description | Notes
|
|||
**isFavorite** | **bool** | | [optional]
|
||||
**latitude** | **num** | | [optional]
|
||||
**longitude** | **num** | | [optional]
|
||||
**orientation** | **num** | | [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)
|
||||
|
||||
|
|
21
mobile/openapi/lib/model/asset_bulk_update_dto.dart
generated
21
mobile/openapi/lib/model/asset_bulk_update_dto.dart
generated
|
@ -19,6 +19,7 @@ class AssetBulkUpdateDto {
|
|||
this.isFavorite,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.orientation,
|
||||
this.removeParent,
|
||||
this.stackParentId,
|
||||
});
|
||||
|
@ -65,6 +66,14 @@ class AssetBulkUpdateDto {
|
|||
///
|
||||
num? longitude;
|
||||
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
num? orientation;
|
||||
|
||||
///
|
||||
/// 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
|
||||
|
@ -89,6 +98,7 @@ class AssetBulkUpdateDto {
|
|||
other.isFavorite == isFavorite &&
|
||||
other.latitude == latitude &&
|
||||
other.longitude == longitude &&
|
||||
other.orientation == orientation &&
|
||||
other.removeParent == removeParent &&
|
||||
other.stackParentId == stackParentId;
|
||||
|
||||
|
@ -101,11 +111,12 @@ class AssetBulkUpdateDto {
|
|||
(isFavorite == null ? 0 : isFavorite!.hashCode) +
|
||||
(latitude == null ? 0 : latitude!.hashCode) +
|
||||
(longitude == null ? 0 : longitude!.hashCode) +
|
||||
(orientation == null ? 0 : orientation!.hashCode) +
|
||||
(removeParent == null ? 0 : removeParent!.hashCode) +
|
||||
(stackParentId == null ? 0 : stackParentId!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'AssetBulkUpdateDto[dateTimeOriginal=$dateTimeOriginal, ids=$ids, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, removeParent=$removeParent, stackParentId=$stackParentId]';
|
||||
String toString() => 'AssetBulkUpdateDto[dateTimeOriginal=$dateTimeOriginal, ids=$ids, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, orientation=$orientation, removeParent=$removeParent, stackParentId=$stackParentId]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
|
@ -135,6 +146,11 @@ class AssetBulkUpdateDto {
|
|||
} else {
|
||||
// json[r'longitude'] = null;
|
||||
}
|
||||
if (this.orientation != null) {
|
||||
json[r'orientation'] = this.orientation;
|
||||
} else {
|
||||
// json[r'orientation'] = null;
|
||||
}
|
||||
if (this.removeParent != null) {
|
||||
json[r'removeParent'] = this.removeParent;
|
||||
} else {
|
||||
|
@ -168,6 +184,9 @@ class AssetBulkUpdateDto {
|
|||
longitude: json[r'longitude'] == null
|
||||
? null
|
||||
: num.parse(json[r'longitude'].toString()),
|
||||
orientation: json[r'orientation'] == null
|
||||
? null
|
||||
: num.parse(json[r'orientation'].toString()),
|
||||
removeParent: mapValueOfType<bool>(json, r'removeParent'),
|
||||
stackParentId: mapValueOfType<String>(json, r'stackParentId'),
|
||||
);
|
||||
|
|
25
mobile/openapi/lib/model/update_asset_dto.dart
generated
25
mobile/openapi/lib/model/update_asset_dto.dart
generated
|
@ -19,6 +19,7 @@ class UpdateAssetDto {
|
|||
this.isFavorite,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.orientation,
|
||||
});
|
||||
|
||||
///
|
||||
|
@ -69,6 +70,14 @@ class UpdateAssetDto {
|
|||
///
|
||||
num? longitude;
|
||||
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
num? orientation;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is UpdateAssetDto &&
|
||||
other.dateTimeOriginal == dateTimeOriginal &&
|
||||
|
@ -76,7 +85,8 @@ class UpdateAssetDto {
|
|||
other.isArchived == isArchived &&
|
||||
other.isFavorite == isFavorite &&
|
||||
other.latitude == latitude &&
|
||||
other.longitude == longitude;
|
||||
other.longitude == longitude &&
|
||||
other.orientation == orientation;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
|
@ -86,10 +96,11 @@ class UpdateAssetDto {
|
|||
(isArchived == null ? 0 : isArchived!.hashCode) +
|
||||
(isFavorite == null ? 0 : isFavorite!.hashCode) +
|
||||
(latitude == null ? 0 : latitude!.hashCode) +
|
||||
(longitude == null ? 0 : longitude!.hashCode);
|
||||
(longitude == null ? 0 : longitude!.hashCode) +
|
||||
(orientation == null ? 0 : orientation!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'UpdateAssetDto[dateTimeOriginal=$dateTimeOriginal, description=$description, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude]';
|
||||
String toString() => 'UpdateAssetDto[dateTimeOriginal=$dateTimeOriginal, description=$description, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, orientation=$orientation]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
|
@ -123,6 +134,11 @@ class UpdateAssetDto {
|
|||
} else {
|
||||
// json[r'longitude'] = null;
|
||||
}
|
||||
if (this.orientation != null) {
|
||||
json[r'orientation'] = this.orientation;
|
||||
} else {
|
||||
// json[r'orientation'] = null;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
|
@ -144,6 +160,9 @@ class UpdateAssetDto {
|
|||
longitude: json[r'longitude'] == null
|
||||
? null
|
||||
: num.parse(json[r'longitude'].toString()),
|
||||
orientation: json[r'orientation'] == null
|
||||
? null
|
||||
: num.parse(json[r'orientation'].toString()),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -46,6 +46,11 @@ void main() {
|
|||
// TODO
|
||||
});
|
||||
|
||||
// num orientation
|
||||
test('to test the property `orientation`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// bool removeParent
|
||||
test('to test the property `removeParent`', () async {
|
||||
// TODO
|
||||
|
|
5
mobile/openapi/test/update_asset_dto_test.dart
generated
5
mobile/openapi/test/update_asset_dto_test.dart
generated
|
@ -46,6 +46,11 @@ void main() {
|
|||
// TODO
|
||||
});
|
||||
|
||||
// num orientation
|
||||
test('to test the property `orientation`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -6471,6 +6471,9 @@
|
|||
"longitude": {
|
||||
"type": "number"
|
||||
},
|
||||
"orientation": {
|
||||
"type": "number"
|
||||
},
|
||||
"removeParent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
@ -9369,6 +9372,9 @@
|
|||
},
|
||||
"longitude": {
|
||||
"type": "number"
|
||||
},
|
||||
"orientation": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
|
|
|
@ -393,8 +393,8 @@ export class AssetService {
|
|||
async update(authUser: AuthUserDto, id: string, dto: UpdateAssetDto): Promise<AssetResponseDto> {
|
||||
await this.access.requirePermission(authUser, Permission.ASSET_UPDATE, id);
|
||||
|
||||
const { description, dateTimeOriginal, latitude, longitude, ...rest } = dto;
|
||||
await this.updateMetadata({ id, description, dateTimeOriginal, latitude, longitude });
|
||||
const { description, dateTimeOriginal, latitude, longitude, orientation, ...rest } = dto;
|
||||
await this.updateMetadata({ id, description, dateTimeOriginal, latitude, longitude, orientation });
|
||||
|
||||
const asset = await this.assetRepository.save({ id, ...rest });
|
||||
await this.jobRepository.queue({ name: JobName.SEARCH_INDEX_ASSET, data: { ids: [id] } });
|
||||
|
@ -402,7 +402,7 @@ export class AssetService {
|
|||
}
|
||||
|
||||
async updateAll(authUser: AuthUserDto, dto: AssetBulkUpdateDto): Promise<void> {
|
||||
const { ids, removeParent, dateTimeOriginal, latitude, longitude, ...options } = dto;
|
||||
const { ids, removeParent, dateTimeOriginal, latitude, longitude, orientation, ...options } = dto;
|
||||
await this.access.requirePermission(authUser, Permission.ASSET_UPDATE, ids);
|
||||
|
||||
if (removeParent) {
|
||||
|
@ -423,7 +423,7 @@ export class AssetService {
|
|||
}
|
||||
|
||||
for (const id of ids) {
|
||||
await this.updateMetadata({ id, dateTimeOriginal, latitude, longitude });
|
||||
await this.updateMetadata({ id, dateTimeOriginal, latitude, longitude, orientation });
|
||||
}
|
||||
|
||||
await this.jobRepository.queue({ name: JobName.SEARCH_INDEX_ASSET, data: { ids } });
|
||||
|
@ -591,8 +591,9 @@ export class AssetService {
|
|||
}
|
||||
|
||||
private async updateMetadata(dto: ISidecarWriteJob) {
|
||||
const { id, description, dateTimeOriginal, latitude, longitude } = dto;
|
||||
const writes = _.omitBy({ description, dateTimeOriginal, latitude, longitude }, _.isUndefined);
|
||||
const { id, description, dateTimeOriginal, latitude, longitude, orientation } = dto;
|
||||
const writes = _.omitBy({ description, dateTimeOriginal, latitude, longitude, orientation }, _.isUndefined);
|
||||
console.log('updatemetadta', orientation);
|
||||
if (Object.keys(writes).length > 0) {
|
||||
await this.assetRepository.upsertExif({ assetId: id, ...writes });
|
||||
await this.jobRepository.queue({ name: JobName.SIDECAR_WRITE, data: { id, ...writes } });
|
||||
|
|
|
@ -202,6 +202,11 @@ export class AssetBulkUpdateDto extends BulkIdsDto {
|
|||
@IsLongitude()
|
||||
@IsNotEmpty()
|
||||
longitude?: number;
|
||||
|
||||
@Optional()
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
orientation?: number;
|
||||
}
|
||||
|
||||
export class UpdateAssetDto {
|
||||
|
@ -230,6 +235,11 @@ export class UpdateAssetDto {
|
|||
@IsLongitude()
|
||||
@IsNotEmpty()
|
||||
longitude?: number;
|
||||
|
||||
@Optional()
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
orientation?: number;
|
||||
}
|
||||
|
||||
export class RandomAssetsDto {
|
||||
|
|
|
@ -39,4 +39,5 @@ export interface ISidecarWriteJob extends IEntityJob {
|
|||
dateTimeOriginal?: string;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
orientation?: number;
|
||||
}
|
||||
|
|
|
@ -245,7 +245,7 @@ export class MetadataService {
|
|||
}
|
||||
|
||||
async handleSidecarWrite(job: ISidecarWriteJob) {
|
||||
const { id, description, dateTimeOriginal, latitude, longitude } = job;
|
||||
const { id, description, dateTimeOriginal, latitude, longitude, orientation } = job;
|
||||
const [asset] = await this.assetRepository.getByIds([id]);
|
||||
if (!asset) {
|
||||
return false;
|
||||
|
@ -258,6 +258,7 @@ export class MetadataService {
|
|||
CreationDate: dateTimeOriginal,
|
||||
GPSLatitude: latitude,
|
||||
GPSLongitude: longitude,
|
||||
Orientation: orientation,
|
||||
},
|
||||
_.isUndefined,
|
||||
);
|
||||
|
|
|
@ -27,6 +27,7 @@ export interface ImmichTags extends Omit<Tags, 'FocalLength' | 'Duration'> {
|
|||
ImagePixelDepth?: string;
|
||||
FocalLength?: number;
|
||||
Duration?: number | ExifDuration;
|
||||
Orientation?: number;
|
||||
}
|
||||
|
||||
export interface IMetadataRepository {
|
||||
|
|
12
web/src/api/open-api/api.ts
generated
12
web/src/api/open-api/api.ts
generated
|
@ -483,6 +483,12 @@ export interface AssetBulkUpdateDto {
|
|||
* @memberof AssetBulkUpdateDto
|
||||
*/
|
||||
'longitude'?: number;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof AssetBulkUpdateDto
|
||||
*/
|
||||
'orientation'?: number;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
|
@ -4191,6 +4197,12 @@ export interface UpdateAssetDto {
|
|||
* @memberof UpdateAssetDto
|
||||
*/
|
||||
'longitude'?: number;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof UpdateAssetDto
|
||||
*/
|
||||
'orientation'?: number;
|
||||
}
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
export let album: AlbumResponseDto | null = null;
|
||||
|
||||
let reactions: ActivityResponseDto[] = [];
|
||||
let rotatePhotoviewer: () => void;
|
||||
let rotatePhotoviewer: () => Promise<void>;
|
||||
const { setAssetId } = assetViewingStore;
|
||||
const {
|
||||
restartProgress: restartSlideshowProgress,
|
||||
|
|
|
@ -6,13 +6,56 @@
|
|||
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
||||
import { useZoomImageWheel } from '@zoom-image/svelte';
|
||||
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
||||
import { isWebCompatibleImage } from '$lib/utils/asset-utils';
|
||||
import { getAssetRatio, isWebCompatibleImage } from '$lib/utils/asset-utils';
|
||||
import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
|
||||
export let asset: AssetResponseDto;
|
||||
export let element: HTMLDivElement | undefined = undefined;
|
||||
export let haveFadeTransition = true;
|
||||
export const rotate = () => setZoomImageWheelState({ currentRotation: $zoomImageWheelState.currentRotation - 90 });
|
||||
|
||||
const getRotation = (value: string): number => {
|
||||
switch (value) {
|
||||
case '1':
|
||||
return 0;
|
||||
case '3':
|
||||
return 180;
|
||||
case '6':
|
||||
return 90;
|
||||
case '8':
|
||||
return 270;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const getRotationString = (rotation: number): number => {
|
||||
switch (rotation % 360) {
|
||||
case 0:
|
||||
return 1;
|
||||
case 90:
|
||||
return 6;
|
||||
case 180:
|
||||
return 3;
|
||||
case 270:
|
||||
return 8;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
export const rotate = async () => {
|
||||
setZoomImageWheelState({ currentRotation: $zoomImageWheelState.currentRotation - 90 });
|
||||
console.log(getRotationString($zoomImageWheelState.currentRotation));
|
||||
try {
|
||||
await api.assetApi.updateAsset({
|
||||
id: asset.id,
|
||||
updateAssetDto: { orientation: getRotationString($zoomImageWheelState.currentRotation) },
|
||||
});
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to change orientation');
|
||||
}
|
||||
};
|
||||
|
||||
let imgElement: HTMLDivElement;
|
||||
let assetData: string;
|
||||
|
@ -115,6 +158,16 @@
|
|||
maxZoom: 10,
|
||||
wheelZoomRatio: 0.2,
|
||||
});
|
||||
if (asset.exifInfo?.orientation) {
|
||||
const { width, height } = getAssetRatio(asset);
|
||||
if (width > height && parseInt(asset.exifInfo?.orientation) != 1) {
|
||||
setZoomImageWheelState({ currentRotation: getRotation(asset.exifInfo?.orientation) });
|
||||
}
|
||||
|
||||
if (width < height && parseInt(asset.exifInfo?.orientation) != 6) {
|
||||
setZoomImageWheelState({ currentRotation: getRotation(asset.exifInfo?.orientation) });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
Loading…
Reference in a new issue