|
@@ -2,6 +2,7 @@ import 'dart:async';
|
|
|
import 'dart:core';
|
|
|
import 'dart:io';
|
|
|
|
|
|
+import "package:collection/collection.dart";
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
import 'package:logging/logging.dart';
|
|
|
import 'package:photos/core/configuration.dart';
|
|
@@ -11,7 +12,11 @@ import 'package:photos/db/file_updation_db.dart';
|
|
|
import 'package:photos/db/files_db.dart';
|
|
|
import 'package:photos/extensions/stop_watch.dart';
|
|
|
import 'package:photos/models/file.dart' as ente;
|
|
|
+import "package:photos/models/location/location.dart";
|
|
|
+import "package:photos/models/magic_metadata.dart";
|
|
|
+import "package:photos/services/file_magic_service.dart";
|
|
|
import 'package:photos/services/files_service.dart';
|
|
|
+import "package:photos/utils/exif_util.dart";
|
|
|
import 'package:photos/utils/file_uploader_util.dart';
|
|
|
import 'package:photos/utils/file_util.dart';
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
@@ -27,6 +32,9 @@ class LocalFileUpdateService {
|
|
|
static const isBadCreationTimeImportDone = 'fm_badCreationTime';
|
|
|
static const isBadCreationTimeMigrationComplete =
|
|
|
'fm_badCreationTimeCompleted';
|
|
|
+ static const isMissingLocationV2ImportDone = "fm_missingLocationV2ImportDone";
|
|
|
+ static const isMissingLocationV2MigrationDone =
|
|
|
+ "fm_missingLocationV2MigrationDone";
|
|
|
Completer<void>? _existingMigration;
|
|
|
|
|
|
LocalFileUpdateService._privateConstructor() {
|
|
@@ -55,6 +63,7 @@ class LocalFileUpdateService {
|
|
|
await _markFilesWhichAreActuallyUpdated();
|
|
|
if (Platform.isAndroid) {
|
|
|
await _migrationForFixingBadCreationTime();
|
|
|
+ await _migrationFilesWithMissingLocationV2();
|
|
|
}
|
|
|
} catch (e, s) {
|
|
|
_logger.severe('failed to perform migration', e, s);
|
|
@@ -210,4 +219,90 @@ class LocalFileUpdateService {
|
|
|
watch.log("imported ${filesGeneratedID.length} files");
|
|
|
_prefs.setBool(isBadCreationTimeImportDone, true);
|
|
|
}
|
|
|
+
|
|
|
+ Future<void> _migrationFilesWithMissingLocationV2() async {
|
|
|
+ if (_prefs.containsKey(isMissingLocationV2MigrationDone)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ await _importForMissingLocationV2();
|
|
|
+ const int singleRunLimit = 10;
|
|
|
+ final List<String> processedIDs = [];
|
|
|
+ try {
|
|
|
+ final localIDs = await _fileUpdationDB.getLocalIDsForPotentialReUpload(
|
|
|
+ singleRunLimit,
|
|
|
+ FileUpdationDB.missingLocationV2,
|
|
|
+ );
|
|
|
+ if (localIDs.isEmpty) {
|
|
|
+ // everything is done
|
|
|
+ await _prefs.setBool(isBadCreationTimeMigrationComplete, true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ final List<ente.File> enteFiles = await FilesDB.instance
|
|
|
+ .getFilesForLocalIDs(localIDs, Configuration.instance.getUserID()!);
|
|
|
+ // fine localIDs which are not present in enteFiles
|
|
|
+ final List<String> missingLocalIDs = [];
|
|
|
+ for (String localID in localIDs) {
|
|
|
+ if (enteFiles.firstWhereOrNull((e) => e.localID == localID) == null) {
|
|
|
+ missingLocalIDs.add(localID);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ processedIDs.addAll(missingLocalIDs);
|
|
|
+
|
|
|
+ final List<ente.File> remoteFilesToUpdate = [];
|
|
|
+ final Map<int, Map<String, double>> fileIDToUpdateMetadata = {};
|
|
|
+
|
|
|
+ for (ente.File file in enteFiles) {
|
|
|
+ final Location? location = await tryLocationFromExif(file);
|
|
|
+ if (location != null &&
|
|
|
+ (location.latitude ?? 0) != 0.0 &&
|
|
|
+ (location.longitude ?? 0) != 0.0) {
|
|
|
+ remoteFilesToUpdate.add(file);
|
|
|
+ fileIDToUpdateMetadata[file.uploadedFileID!] = {
|
|
|
+ pubMagicKeyLat: location.latitude!,
|
|
|
+ pubMagicKeyLong: location.longitude!
|
|
|
+ };
|
|
|
+ } else if (file.localID != null) {
|
|
|
+ processedIDs.add(file.localID!);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (remoteFilesToUpdate.isNotEmpty) {
|
|
|
+ await FileMagicService.instance.updatePublicMagicMetadata(
|
|
|
+ remoteFilesToUpdate,
|
|
|
+ null,
|
|
|
+ metadataUpdateMap: fileIDToUpdateMetadata,
|
|
|
+ );
|
|
|
+ for (ente.File file in remoteFilesToUpdate) {
|
|
|
+ if (file.localID != null) {
|
|
|
+ processedIDs.add(file.localID!);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ _logger.severe("Failed to fix bad creationTime", e);
|
|
|
+ } finally {
|
|
|
+ await _fileUpdationDB.deleteByLocalIDs(
|
|
|
+ processedIDs,
|
|
|
+ FileUpdationDB.missingLocationV2,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Future<void> _importForMissingLocationV2() async {
|
|
|
+ if (_prefs.containsKey(isMissingLocationV2ImportDone)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _logger.info('_importForMissingLocationV2');
|
|
|
+ final EnteWatch watch = EnteWatch("_importForMissingLocationV2");
|
|
|
+ final int ownerID = Configuration.instance.getUserID()!;
|
|
|
+ final List<String> localIDs =
|
|
|
+ await FilesDB.instance.getLocalIDsForFilesWithoutLocation(ownerID);
|
|
|
+
|
|
|
+ await _fileUpdationDB.insertMultiple(
|
|
|
+ localIDs,
|
|
|
+ FileUpdationDB.missingLocationV2,
|
|
|
+ );
|
|
|
+ watch.log("imported ${localIDs.length} files");
|
|
|
+ await _prefs.setBool(isMissingLocationV2ImportDone, true);
|
|
|
+ }
|
|
|
}
|