From c1915b393a53a5f82c9e3e8672bcee4ffa09d392 Mon Sep 17 00:00:00 2001 From: Ming Ming Date: Sat, 23 Nov 2024 00:43:36 +0800 Subject: [PATCH] Fallback to our metadata extractor if file not supported by nextcloud server --- .../use_case/sync_metadata/sync_by_app.dart | 40 +++++++++---------- .../sync_metadata/sync_by_server.dart | 32 +++++++++++---- .../use_case/sync_metadata/sync_metadata.dart | 13 +++++- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/app/lib/use_case/sync_metadata/sync_by_app.dart b/app/lib/use_case/sync_metadata/sync_by_app.dart index d7106905..e6e37347 100644 --- a/app/lib/use_case/sync_metadata/sync_by_app.dart +++ b/app/lib/use_case/sync_metadata/sync_by_app.dart @@ -34,8 +34,12 @@ class _SyncByApp { account: account.toDb(), fileIds: fileIds, ); - for (final f in files) { - final result = await _syncOne(f); + for (final dbF in files) { + final f = DbFileConverter.fromDb( + account.userId.toCaseInsensitiveString(), + dbF, + ); + final result = await syncOne(f); if (result != null) { yield result; } @@ -45,16 +49,12 @@ class _SyncByApp { } } - Future _syncOne(DbFile file) async { - final f = DbFileConverter.fromDb( - account.userId.toCaseInsensitiveString(), - file, - ); - _log.fine("[_syncOne] Syncing ${file.relativePath}"); + Future syncOne(File file) async { + _log.fine("[syncOne] Syncing ${file.path}"); try { OrNull? metadataUpdate; OrNull? locationUpdate; - if (f.metadata == null) { + if (file.metadata == null) { // since we need to download multiple images in their original size, // we only do it with WiFi await wifiEnsurer(); @@ -62,21 +62,21 @@ class _SyncByApp { if (!_shouldRun) { return null; } - _log.fine("[_syncOne] Updating metadata for ${f.path}"); - final binary = await GetFileBinary(fileRepo)(account, f); + _log.fine("[syncOne] Updating metadata for ${file.path}"); + final binary = await GetFileBinary(fileRepo)(account, file); final metadata = - (await LoadMetadata().loadRemote(account, f, binary)).copyWith( - fileEtag: f.etag, + (await LoadMetadata().loadRemote(account, file, binary)).copyWith( + fileEtag: file.etag, ); metadataUpdate = OrNull(metadata); } - final lat = (metadataUpdate?.obj ?? f.metadata)?.exif?.gpsLatitudeDeg; - final lng = (metadataUpdate?.obj ?? f.metadata)?.exif?.gpsLongitudeDeg; + final lat = (metadataUpdate?.obj ?? file.metadata)?.exif?.gpsLatitudeDeg; + final lng = (metadataUpdate?.obj ?? file.metadata)?.exif?.gpsLongitudeDeg; try { ImageLocation? location; if (lat != null && lng != null) { - _log.fine("[_syncOne] Reverse geocoding for ${f.path}"); + _log.fine("[syncOne] Reverse geocoding for ${file.path}"); final l = await _geocoder(lat, lng); if (l != null) { location = l.toImageLocation(); @@ -84,7 +84,7 @@ class _SyncByApp { } locationUpdate = OrNull(location ?? ImageLocation.empty()); } catch (e, stackTrace) { - _log.severe("[_syncOne] Failed while reverse geocoding: ${f.path}", e, + _log.severe("[syncOne] Failed while reverse geocoding: ${file.path}", e, stackTrace); // if failed, we skip updating the location } @@ -92,16 +92,16 @@ class _SyncByApp { if (metadataUpdate != null || locationUpdate != null) { await UpdateProperty(fileRepo: fileRepo2)( account, - f, + file, metadata: metadataUpdate, location: locationUpdate, ); - return f; + return file; } else { return null; } } catch (e, stackTrace) { - _log.severe("[_syncOne] Failed while updating metadata: ${f.path}", e, + _log.severe("[syncOne] Failed while updating metadata: ${file.path}", e, stackTrace); return null; } diff --git a/app/lib/use_case/sync_metadata/sync_by_server.dart b/app/lib/use_case/sync_metadata/sync_by_server.dart index cb4956f6..92debc87 100644 --- a/app/lib/use_case/sync_metadata/sync_by_server.dart +++ b/app/lib/use_case/sync_metadata/sync_by_server.dart @@ -9,6 +9,7 @@ class _SyncByServer { required this.fileRepo2, required this.db, this.interrupter, + required this.fallback, }) { interrupter?.listen((event) { _shouldRun = false; @@ -20,17 +21,20 @@ class _SyncByServer { } Stream syncFiles({ + required List fileIds, required List relativePaths, }) async* { final dirs = relativePaths.map(dirname).toSet(); for (final dir in dirs) { yield* _syncDir( + fileIds: fileIds, dir: File(path: file_util.unstripPath(account, dir)), ); } } Stream _syncDir({ + required List fileIds, required File dir, }) async* { try { @@ -38,15 +42,22 @@ class _SyncByServer { final files = await fileRepoRemote.list(account, dir); await FileSqliteCacheUpdater(db)(account, dir, remote: files); for (final f in files) { - if (f.metadata != null && f.location == null) { - final result = await _syncOne(f); - if (result != null) { - yield result; - } - if (!_shouldRun) { - return; + File? result; + if (!_supportedMimes.contains(f.fdMime)) { + _log.info( + "[_syncDir] File ${f.path} (mime: ${f.fdMime}) not supported by server, fallback to client"); + result = await fallback.syncOne(f); + } else { + if (f.metadata != null && f.location == null) { + result = await _syncOne(f); } } + if (result != null) { + yield result; + } + if (!_shouldRun) { + return; + } } } catch (e, stackTrace) { _log.severe("[_syncDir] Failed to sync dir: $dir", e, stackTrace); @@ -54,6 +65,7 @@ class _SyncByServer { } Future _syncOne(File file) async { + _log.fine("[_syncOne] Syncing ${file.path}"); try { final lat = file.metadata!.exif?.gpsLatitudeDeg; final lng = file.metadata!.exif?.gpsLongitudeDeg; @@ -85,7 +97,13 @@ class _SyncByServer { final FileRepo2 fileRepo2; final NpDb db; final Stream? interrupter; + final _SyncByApp fallback; final _geocoder = ReverseGeocoder(); var _shouldRun = true; + + static const _supportedMimes = [ + "image/jpeg", + "image/webp", + ]; } diff --git a/app/lib/use_case/sync_metadata/sync_metadata.dart b/app/lib/use_case/sync_metadata/sync_metadata.dart index cacc76d9..305b8ed2 100644 --- a/app/lib/use_case/sync_metadata/sync_metadata.dart +++ b/app/lib/use_case/sync_metadata/sync_metadata.dart @@ -48,7 +48,7 @@ class SyncMetadata { } final files = await db.getFilesByMissingMetadata( account: account.toDb(), - mimes: file_util.metadataSupportedFormatMimes, + mimes: file_util.supportedImageFormatMimes, ownerId: account.userId.toCaseInsensitiveString(), ); _log.info("[syncAccount] Missing count: ${files.items.length}"); @@ -79,12 +79,23 @@ class SyncMetadata { Stream _doWithServer( Account account, DbFileMissingMetadataResult files) async* { + final fallback = _SyncByApp( + account: account, + fileRepo: fileRepo, + fileRepo2: fileRepo2, + db: db, + interrupter: interrupter, + wifiEnsurer: wifiEnsurer, + batteryEnsurer: batteryEnsurer, + ); + await fallback.init(); final op = _SyncByServer( account: account, fileRepoRemote: fileRepoRemote, fileRepo2: fileRepo2, db: db, interrupter: interrupter, + fallback: fallback, ); await op.init(); final stream = op.syncFiles(