Fallback to our metadata extractor if file not supported by nextcloud server

This commit is contained in:
Ming Ming 2024-11-23 00:43:36 +08:00
parent 114b52d0e9
commit c1915b393a
3 changed files with 57 additions and 28 deletions

View file

@ -34,8 +34,12 @@ class _SyncByApp {
account: account.toDb(), account: account.toDb(),
fileIds: fileIds, fileIds: fileIds,
); );
for (final f in files) { for (final dbF in files) {
final result = await _syncOne(f); final f = DbFileConverter.fromDb(
account.userId.toCaseInsensitiveString(),
dbF,
);
final result = await syncOne(f);
if (result != null) { if (result != null) {
yield result; yield result;
} }
@ -45,16 +49,12 @@ class _SyncByApp {
} }
} }
Future<File?> _syncOne(DbFile file) async { Future<File?> syncOne(File file) async {
final f = DbFileConverter.fromDb( _log.fine("[syncOne] Syncing ${file.path}");
account.userId.toCaseInsensitiveString(),
file,
);
_log.fine("[_syncOne] Syncing ${file.relativePath}");
try { try {
OrNull<Metadata>? metadataUpdate; OrNull<Metadata>? metadataUpdate;
OrNull<ImageLocation>? locationUpdate; OrNull<ImageLocation>? locationUpdate;
if (f.metadata == null) { if (file.metadata == null) {
// since we need to download multiple images in their original size, // since we need to download multiple images in their original size,
// we only do it with WiFi // we only do it with WiFi
await wifiEnsurer(); await wifiEnsurer();
@ -62,21 +62,21 @@ class _SyncByApp {
if (!_shouldRun) { if (!_shouldRun) {
return null; return null;
} }
_log.fine("[_syncOne] Updating metadata for ${f.path}"); _log.fine("[syncOne] Updating metadata for ${file.path}");
final binary = await GetFileBinary(fileRepo)(account, f); final binary = await GetFileBinary(fileRepo)(account, file);
final metadata = final metadata =
(await LoadMetadata().loadRemote(account, f, binary)).copyWith( (await LoadMetadata().loadRemote(account, file, binary)).copyWith(
fileEtag: f.etag, fileEtag: file.etag,
); );
metadataUpdate = OrNull(metadata); metadataUpdate = OrNull(metadata);
} }
final lat = (metadataUpdate?.obj ?? f.metadata)?.exif?.gpsLatitudeDeg; final lat = (metadataUpdate?.obj ?? file.metadata)?.exif?.gpsLatitudeDeg;
final lng = (metadataUpdate?.obj ?? f.metadata)?.exif?.gpsLongitudeDeg; final lng = (metadataUpdate?.obj ?? file.metadata)?.exif?.gpsLongitudeDeg;
try { try {
ImageLocation? location; ImageLocation? location;
if (lat != null && lng != null) { 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); final l = await _geocoder(lat, lng);
if (l != null) { if (l != null) {
location = l.toImageLocation(); location = l.toImageLocation();
@ -84,7 +84,7 @@ class _SyncByApp {
} }
locationUpdate = OrNull(location ?? ImageLocation.empty()); locationUpdate = OrNull(location ?? ImageLocation.empty());
} catch (e, stackTrace) { } catch (e, stackTrace) {
_log.severe("[_syncOne] Failed while reverse geocoding: ${f.path}", e, _log.severe("[syncOne] Failed while reverse geocoding: ${file.path}", e,
stackTrace); stackTrace);
// if failed, we skip updating the location // if failed, we skip updating the location
} }
@ -92,16 +92,16 @@ class _SyncByApp {
if (metadataUpdate != null || locationUpdate != null) { if (metadataUpdate != null || locationUpdate != null) {
await UpdateProperty(fileRepo: fileRepo2)( await UpdateProperty(fileRepo: fileRepo2)(
account, account,
f, file,
metadata: metadataUpdate, metadata: metadataUpdate,
location: locationUpdate, location: locationUpdate,
); );
return f; return file;
} else { } else {
return null; return null;
} }
} catch (e, stackTrace) { } catch (e, stackTrace) {
_log.severe("[_syncOne] Failed while updating metadata: ${f.path}", e, _log.severe("[syncOne] Failed while updating metadata: ${file.path}", e,
stackTrace); stackTrace);
return null; return null;
} }

View file

@ -9,6 +9,7 @@ class _SyncByServer {
required this.fileRepo2, required this.fileRepo2,
required this.db, required this.db,
this.interrupter, this.interrupter,
required this.fallback,
}) { }) {
interrupter?.listen((event) { interrupter?.listen((event) {
_shouldRun = false; _shouldRun = false;
@ -20,17 +21,20 @@ class _SyncByServer {
} }
Stream<File> syncFiles({ Stream<File> syncFiles({
required List<int> fileIds,
required List<String> relativePaths, required List<String> relativePaths,
}) async* { }) async* {
final dirs = relativePaths.map(dirname).toSet(); final dirs = relativePaths.map(dirname).toSet();
for (final dir in dirs) { for (final dir in dirs) {
yield* _syncDir( yield* _syncDir(
fileIds: fileIds,
dir: File(path: file_util.unstripPath(account, dir)), dir: File(path: file_util.unstripPath(account, dir)),
); );
} }
} }
Stream<File> _syncDir({ Stream<File> _syncDir({
required List<int> fileIds,
required File dir, required File dir,
}) async* { }) async* {
try { try {
@ -38,15 +42,22 @@ class _SyncByServer {
final files = await fileRepoRemote.list(account, dir); final files = await fileRepoRemote.list(account, dir);
await FileSqliteCacheUpdater(db)(account, dir, remote: files); await FileSqliteCacheUpdater(db)(account, dir, remote: files);
for (final f in files) { for (final f in files) {
if (f.metadata != null && f.location == null) { File? result;
final result = await _syncOne(f); if (!_supportedMimes.contains(f.fdMime)) {
if (result != null) { _log.info(
yield result; "[_syncDir] File ${f.path} (mime: ${f.fdMime}) not supported by server, fallback to client");
} result = await fallback.syncOne(f);
if (!_shouldRun) { } else {
return; if (f.metadata != null && f.location == null) {
result = await _syncOne(f);
} }
} }
if (result != null) {
yield result;
}
if (!_shouldRun) {
return;
}
} }
} catch (e, stackTrace) { } catch (e, stackTrace) {
_log.severe("[_syncDir] Failed to sync dir: $dir", e, stackTrace); _log.severe("[_syncDir] Failed to sync dir: $dir", e, stackTrace);
@ -54,6 +65,7 @@ class _SyncByServer {
} }
Future<File?> _syncOne(File file) async { Future<File?> _syncOne(File file) async {
_log.fine("[_syncOne] Syncing ${file.path}");
try { try {
final lat = file.metadata!.exif?.gpsLatitudeDeg; final lat = file.metadata!.exif?.gpsLatitudeDeg;
final lng = file.metadata!.exif?.gpsLongitudeDeg; final lng = file.metadata!.exif?.gpsLongitudeDeg;
@ -85,7 +97,13 @@ class _SyncByServer {
final FileRepo2 fileRepo2; final FileRepo2 fileRepo2;
final NpDb db; final NpDb db;
final Stream<void>? interrupter; final Stream<void>? interrupter;
final _SyncByApp fallback;
final _geocoder = ReverseGeocoder(); final _geocoder = ReverseGeocoder();
var _shouldRun = true; var _shouldRun = true;
static const _supportedMimes = [
"image/jpeg",
"image/webp",
];
} }

View file

@ -48,7 +48,7 @@ class SyncMetadata {
} }
final files = await db.getFilesByMissingMetadata( final files = await db.getFilesByMissingMetadata(
account: account.toDb(), account: account.toDb(),
mimes: file_util.metadataSupportedFormatMimes, mimes: file_util.supportedImageFormatMimes,
ownerId: account.userId.toCaseInsensitiveString(), ownerId: account.userId.toCaseInsensitiveString(),
); );
_log.info("[syncAccount] Missing count: ${files.items.length}"); _log.info("[syncAccount] Missing count: ${files.items.length}");
@ -79,12 +79,23 @@ class SyncMetadata {
Stream<File> _doWithServer( Stream<File> _doWithServer(
Account account, DbFileMissingMetadataResult files) async* { 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( final op = _SyncByServer(
account: account, account: account,
fileRepoRemote: fileRepoRemote, fileRepoRemote: fileRepoRemote,
fileRepo2: fileRepo2, fileRepo2: fileRepo2,
db: db, db: db,
interrupter: interrupter, interrupter: interrupter,
fallback: fallback,
); );
await op.init(); await op.init();
final stream = op.syncFiles( final stream = op.syncFiles(