diff --git a/mobile/lib/infrastructure/repositories/sync_stream.repository.dart b/mobile/lib/infrastructure/repositories/sync_stream.repository.dart index 7aa8fc6efe..067140d44b 100644 --- a/mobile/lib/infrastructure/repositories/sync_stream.repository.dart +++ b/mobile/lib/infrastructure/repositories/sync_stream.repository.dart @@ -169,7 +169,8 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository type: Value(asset.type.toAssetType()), createdAt: Value.absentIfNull(asset.fileCreatedAt), updatedAt: Value.absentIfNull(asset.fileModifiedAt), - durationInSeconds: const Value(0), + durationInSeconds: + Value(asset.duration?.toDuration()?.inSeconds ?? 0), checksum: Value(asset.checksum), isFavorite: Value(asset.isFavorite), ownerId: Value(asset.ownerId), @@ -251,3 +252,17 @@ extension on api.AssetVisibility { _ => throw Exception('Unknown AssetVisibility value: $this'), }; } + +extension on String { + Duration? toDuration() { + try { + final parts = split(':') + .map((e) => double.parse(e).toInt()) + .toList(growable: false); + + return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]); + } catch (_) { + return null; + } + } +} diff --git a/mobile/openapi/lib/model/sync_asset_v1.dart b/mobile/openapi/lib/model/sync_asset_v1.dart index 27042325ee..1ca6e20cff 100644 --- a/mobile/openapi/lib/model/sync_asset_v1.dart +++ b/mobile/openapi/lib/model/sync_asset_v1.dart @@ -15,6 +15,7 @@ class SyncAssetV1 { SyncAssetV1({ required this.checksum, required this.deletedAt, + required this.duration, required this.fileCreatedAt, required this.fileModifiedAt, required this.id, @@ -31,6 +32,8 @@ class SyncAssetV1 { DateTime? deletedAt; + String? duration; + DateTime? fileCreatedAt; DateTime? fileModifiedAt; @@ -55,6 +58,7 @@ class SyncAssetV1 { bool operator ==(Object other) => identical(this, other) || other is SyncAssetV1 && other.checksum == checksum && other.deletedAt == deletedAt && + other.duration == duration && other.fileCreatedAt == fileCreatedAt && other.fileModifiedAt == fileModifiedAt && other.id == id && @@ -71,6 +75,7 @@ class SyncAssetV1 { // ignore: unnecessary_parenthesis (checksum.hashCode) + (deletedAt == null ? 0 : deletedAt!.hashCode) + + (duration == null ? 0 : duration!.hashCode) + (fileCreatedAt == null ? 0 : fileCreatedAt!.hashCode) + (fileModifiedAt == null ? 0 : fileModifiedAt!.hashCode) + (id.hashCode) + @@ -83,7 +88,7 @@ class SyncAssetV1 { (visibility.hashCode); @override - String toString() => 'SyncAssetV1[checksum=$checksum, deletedAt=$deletedAt, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, id=$id, isFavorite=$isFavorite, localDateTime=$localDateTime, originalFileName=$originalFileName, ownerId=$ownerId, thumbhash=$thumbhash, type=$type, visibility=$visibility]'; + String toString() => 'SyncAssetV1[checksum=$checksum, deletedAt=$deletedAt, duration=$duration, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, id=$id, isFavorite=$isFavorite, localDateTime=$localDateTime, originalFileName=$originalFileName, ownerId=$ownerId, thumbhash=$thumbhash, type=$type, visibility=$visibility]'; Map toJson() { final json = {}; @@ -93,6 +98,11 @@ class SyncAssetV1 { } else { // json[r'deletedAt'] = null; } + if (this.duration != null) { + json[r'duration'] = this.duration; + } else { + // json[r'duration'] = null; + } if (this.fileCreatedAt != null) { json[r'fileCreatedAt'] = this.fileCreatedAt!.toUtc().toIso8601String(); } else { @@ -133,6 +143,7 @@ class SyncAssetV1 { return SyncAssetV1( checksum: mapValueOfType(json, r'checksum')!, deletedAt: mapDateTime(json, r'deletedAt', r''), + duration: mapValueOfType(json, r'duration'), fileCreatedAt: mapDateTime(json, r'fileCreatedAt', r''), fileModifiedAt: mapDateTime(json, r'fileModifiedAt', r''), id: mapValueOfType(json, r'id')!, @@ -192,6 +203,7 @@ class SyncAssetV1 { static const requiredKeys = { 'checksum', 'deletedAt', + 'duration', 'fileCreatedAt', 'fileModifiedAt', 'id', diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 242845761d..3ab1a0ce74 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -13622,6 +13622,10 @@ "nullable": true, "type": "string" }, + "duration": { + "nullable": true, + "type": "string" + }, "fileCreatedAt": { "format": "date-time", "nullable": true, @@ -13671,6 +13675,7 @@ "required": [ "checksum", "deletedAt", + "duration", "fileCreatedAt", "fileModifiedAt", "id", diff --git a/server/src/database.ts b/server/src/database.ts index 4e40e5c241..87509bd72a 100644 --- a/server/src/database.ts +++ b/server/src/database.ts @@ -352,6 +352,7 @@ export const columns = { 'isFavorite', 'visibility', 'updateId', + 'duration', ], stack: ['stack.id', 'stack.primaryAssetId', 'ownerId'], syncAssetExif: [ diff --git a/server/src/dtos/sync.dto.ts b/server/src/dtos/sync.dto.ts index 3088392c68..050635308e 100644 --- a/server/src/dtos/sync.dto.ts +++ b/server/src/dtos/sync.dto.ts @@ -65,6 +65,7 @@ export class SyncAssetV1 { fileCreatedAt!: Date | null; fileModifiedAt!: Date | null; localDateTime!: Date | null; + duration!: string | null; @ApiProperty({ enumName: 'AssetTypeEnum', enum: AssetType }) type!: AssetType; deletedAt!: Date | null; diff --git a/server/src/queries/sync.repository.sql b/server/src/queries/sync.repository.sql index f9565b6eff..659365c563 100644 --- a/server/src/queries/sync.repository.sql +++ b/server/src/queries/sync.repository.sql @@ -86,7 +86,8 @@ select "deletedAt", "isFavorite", "visibility", - "updateId" + "updateId", + "duration" from "assets" where @@ -109,7 +110,8 @@ select "deletedAt", "isFavorite", "visibility", - "updateId" + "updateId", + "duration" from "assets" where diff --git a/server/test/medium/specs/sync/sync-asset.spec.ts b/server/test/medium/specs/sync/sync-asset.spec.ts index b46ccd97e1..913edac5d9 100644 --- a/server/test/medium/specs/sync/sync-asset.spec.ts +++ b/server/test/medium/specs/sync/sync-asset.spec.ts @@ -38,6 +38,7 @@ describe.concurrent(SyncEntityType.AssetV1, () => { fileModifiedAt: date, localDateTime: date, deletedAt: null, + duration: '0:10:00.00000', }); await assetRepo.create(asset); @@ -61,6 +62,7 @@ describe.concurrent(SyncEntityType.AssetV1, () => { localDateTime: asset.localDateTime, type: asset.type, visibility: asset.visibility, + duration: asset.duration, }, type: 'AssetV1', }, diff --git a/server/test/medium/specs/sync/sync-partner-asset.spec.ts b/server/test/medium/specs/sync/sync-partner-asset.spec.ts index 125047b1bf..8125193ba5 100644 --- a/server/test/medium/specs/sync/sync-partner-asset.spec.ts +++ b/server/test/medium/specs/sync/sync-partner-asset.spec.ts @@ -42,6 +42,7 @@ describe.concurrent(SyncRequestType.PartnerAssetsV1, () => { fileModifiedAt: date, localDateTime: date, deletedAt: null, + duration: '0:10:00.00000', }); await assetRepo.create(asset); @@ -68,6 +69,7 @@ describe.concurrent(SyncRequestType.PartnerAssetsV1, () => { localDateTime: date, type: asset.type, visibility: asset.visibility, + duration: asset.duration, }, type: SyncEntityType.PartnerAssetV1, },