reuse exist checksums on trash data update

handle restoration errors
fix import
This commit is contained in:
Peter Ombodi 2025-10-06 18:28:31 +03:00
parent 172102c438
commit 44ec7744ba
3 changed files with 34 additions and 10 deletions

View file

@ -300,7 +300,6 @@ class LocalSyncService {
return Future.value(); return Future.value();
} }
final trashedAssets = <TrashedAsset>[]; final trashedAssets = <TrashedAsset>[];
//todo try to reuse exist checksums from local assets table before they updated
for (final update in trashUpdates) { for (final update in trashUpdates) {
final albums = delta.assetAlbums.cast<String, List<Object?>>(); final albums = delta.assetAlbums.cast<String, List<Object?>>();
for (final String id in albums[update.id]!.cast<String?>().nonNulls) { for (final String id in albums[update.id]!.cast<String?>().nonNulls) {
@ -329,13 +328,19 @@ class LocalSyncService {
Future<void> _applyRemoteRestoreToLocal() async { Future<void> _applyRemoteRestoreToLocal() async {
final remoteAssetsToRestore = await _trashedLocalAssetRepository.getToRestore(); final remoteAssetsToRestore = await _trashedLocalAssetRepository.getToRestore();
final toRestoreIds = <String>[];
if (remoteAssetsToRestore.isNotEmpty) { if (remoteAssetsToRestore.isNotEmpty) {
_log.info("remoteAssetsToRestore: $remoteAssetsToRestore"); _log.info("remoteAssetsToRestore: $remoteAssetsToRestore");
for (final asset in remoteAssetsToRestore) { for (final asset in remoteAssetsToRestore) {
_log.info("Restoring from trash, localId: ${asset.id}, remoteId: ${asset.checksum}"); _log.info("Restoring from trash, localId: ${asset.id}, remoteId: ${asset.checksum}");
try {
await _localFilesManager.restoreFromTrashById(asset.id, asset.type.index); await _localFilesManager.restoreFromTrashById(asset.id, asset.type.index);
toRestoreIds.add(asset.id);
} catch (e) {
_log.warning("Restoring failure: $e");
} }
await _trashedLocalAssetRepository.restoreLocalAssets(remoteAssetsToRestore.map((e) => e.id)); }
await _trashedLocalAssetRepository.restoreLocalAssets(toRestoreIds);
} else { } else {
_log.info("No remote assets found for restoration"); _log.info("No remote assets found for restoration");
} }

View file

@ -63,14 +63,15 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
await _db.delete(_db.trashedLocalAssetEntity).go(); await _db.delete(_db.trashedLocalAssetEntity).go();
return; return;
} }
Map<String, String> localChecksumById = await _getCachedChecksums(assets);
return _db.transaction(() async { return _db.transaction(() async {
await _db.batch((batch) { await _db.batch((batch) {
for (final asset in assets) { for (final asset in assets) {
final effectiveChecksum = localChecksumById[asset.id] ?? asset.checksum;
final companion = TrashedLocalAssetEntityCompanion.insert( final companion = TrashedLocalAssetEntityCompanion.insert(
id: asset.id, id: asset.id,
albumId: albumId, albumId: albumId,
checksum: asset.checksum == null ? const Value.absent() : Value(asset.checksum), checksum: effectiveChecksum == null ? const Value.absent() : Value(effectiveChecksum),
name: asset.name, name: asset.name,
type: asset.type, type: asset.type,
createdAt: Value(asset.createdAt), createdAt: Value(asset.createdAt),
@ -109,19 +110,22 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
}); });
} }
Future<void> saveTrashedAssets(Iterable<TrashedAsset> trashUpdates) async { Future<void> saveTrashedAssets(Iterable<TrashedAsset> assets) async {
if (trashUpdates.isEmpty) { if (assets.isEmpty) {
return; return;
} }
Map<String, String> localChecksumById = await _getCachedChecksums(assets);
await _db.batch((batch) { await _db.batch((batch) {
for (final asset in trashUpdates) { for (final asset in assets) {
final effectiveChecksum = localChecksumById[asset.id] ?? asset.checksum;
final companion = TrashedLocalAssetEntityCompanion.insert( final companion = TrashedLocalAssetEntityCompanion.insert(
id: asset.id, id: asset.id,
albumId: asset.albumId, albumId: asset.albumId,
name: asset.name, name: asset.name,
type: asset.type, type: asset.type,
checksum: asset.checksum == null ? const Value.absent() : Value(asset.checksum), checksum: effectiveChecksum == null ? const Value.absent() : Value(effectiveChecksum),
createdAt: Value(asset.createdAt), createdAt: Value(asset.createdAt),
width: Value(asset.width), width: Value(asset.width),
height: Value(asset.height), height: Value(asset.height),
@ -175,6 +179,8 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
durationInSeconds: Value(asset.durationInSeconds), durationInSeconds: Value(asset.durationInSeconds),
isFavorite: Value(asset.isFavorite), isFavorite: Value(asset.isFavorite),
orientation: Value(asset.orientation), orientation: Value(asset.orientation),
createdAt: Value(asset.createdAt),
updatedAt: Value(asset.updatedAt),
), ),
); );
} }
@ -229,4 +235,18 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
}); });
}); });
} }
//attempt to reuse existing checksums
Future<Map<String, String>> _getCachedChecksums(Iterable<TrashedAsset> trashUpdates) async {
final ids = trashUpdates.map((e) => e.id).toSet();
final rows = await (_db.selectOnly(_db.localAssetEntity)
..where(_db.localAssetEntity.id.isIn(ids) & _db.localAssetEntity.checksum.isNotNull())
..addColumns([_db.localAssetEntity.id, _db.localAssetEntity.checksum]))
.get();
final localChecksumById = {
for (final r in rows) r.read(_db.localAssetEntity.id)!: r.read(_db.localAssetEntity.checksum)!
};
return localChecksumById;
}
} }

View file

@ -1,5 +1,4 @@
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/asset/trashed_asset.model.dart';
import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/entities/asset.entity.dart' as old; import 'package:immich_mobile/entities/asset.entity.dart' as old;