diff --git a/lib/db/file_updation_db.dart b/lib/db/file_updation_db.dart index c3d2bab4f..46635bf38 100644 --- a/lib/db/file_updation_db.dart +++ b/lib/db/file_updation_db.dart @@ -16,6 +16,7 @@ class FileUpdationDB { static const columnReason = 'reason'; static const missingLocation = 'missing_location'; static const modificationTimeUpdated = 'modificationTimeUpdated'; + static const badCreationTime = 'badCreationTime'; // SQL code to create the database table static List _createTable() { diff --git a/lib/db/files_db.dart b/lib/db/files_db.dart index 18d3af342..08e89e75e 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -1259,6 +1259,28 @@ class FilesDB { return result; } + Future> getFilesFromGeneratedIDs(List ids) async { + final result = {}; + if (ids.isEmpty) { + return result; + } + String inParam = ""; + for (final id in ids) { + inParam += "'" + id.toString() + "',"; + } + inParam = inParam.substring(0, inParam.length - 1); + final db = await instance.database; + final results = await db.query( + filesTable, + where: '$columnGeneratedID IN ($inParam)', + ); + final files = convertToFiles(results); + for (final file in files) { + result[file.generatedID] = file; + } + return result; + } + Future>> getAllFilesGroupByCollectionID( List ids, ) async { @@ -1312,6 +1334,26 @@ class FilesDB { return files; } + Future> getGeneratedIDForFilesOlderThan( + int cutOffTime, + int ownerID, + ) async { + final db = await instance.database; + final rows = await db.query( + filesTable, + columns: [columnGeneratedID], + distinct: true, + where: + '$columnCreationTime <= ? AND ($columnOwnerID IS NULL OR $columnOwnerID = ?)', + whereArgs: [cutOffTime, ownerID], + ); + final result = []; + for (final row in rows) { + result.add(row[columnGeneratedID].toString()); + } + return result; + } + Future> getAllFilesFromDB(Set collectionsToIgnore) async { final db = await instance.database; final List> result = await db.query(filesTable); diff --git a/lib/services/local_file_update_service.dart b/lib/services/local_file_update_service.dart index 45883032c..c41d30bef 100644 --- a/lib/services/local_file_update_service.dart +++ b/lib/services/local_file_update_service.dart @@ -6,9 +6,13 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; +import 'package:photos/core/configuration.dart'; +import 'package:photos/core/constants.dart'; 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/services/files_service.dart'; import 'package:photos/utils/file_uploader_util.dart'; import 'package:photos/utils/file_util.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -21,6 +25,9 @@ class LocalFileUpdateService { Logger _logger; static const isLocationMigrationComplete = "fm_isLocationMigrationComplete"; static const isLocalImportDone = "fm_IsLocalImportDone"; + static const isBadCreationTimeImportDone = 'fm_badCreationTime'; + static const isBadCreationTimeMigrationComplete = + 'fm_badCreationTimeCompleted'; Completer _existingMigration; LocalFileUpdateService._privateConstructor() { @@ -35,8 +42,8 @@ class LocalFileUpdateService { static LocalFileUpdateService instance = LocalFileUpdateService._privateConstructor(); - bool isLocationMigrationCompleted() { - return _prefs.get(isLocationMigrationComplete) ?? false; + bool isBadCreationMigrationCompleted() { + return _prefs.get(isBadCreationTimeMigrationComplete) ?? false; } Future markUpdatedFilesForReUpload() async { @@ -47,6 +54,9 @@ class LocalFileUpdateService { _existingMigration = Completer(); try { await _markFilesWhichAreActuallyUpdated(); + if (Platform.isAndroid) { + await _migrationForFixingBadCreationTime(); + } } catch (e, s) { _logger.severe('failed to perform migration', e, s); } finally { @@ -141,4 +151,54 @@ class LocalFileUpdateService { } return mediaUploadData; } + + Future _migrationForFixingBadCreationTime() async { + if (_prefs.containsKey(isBadCreationTimeMigrationComplete)) { + return; + } + await _importFilesWithBadCreationTime(); + const int singleRunLimit = 100; + try { + final generatedIDs = + await _fileUpdationDB.getLocalIDsForPotentialReUpload( + singleRunLimit, + FileUpdationDB.badCreationTime, + ); + if (generatedIDs.isNotEmpty) { + final List genIdIntList = + generatedIDs.map((e) => int.tryParse(e)).toList(); + final filesWithBadTime = + await FilesDB.instance.getFilesFromGeneratedIDs(genIdIntList); + await FilesService.instance.bulkEditTime( + filesWithBadTime.values.toList(), EditTimeSource.fileName); + } else { + // everything is done + await _prefs.setBool(isBadCreationTimeMigrationComplete, true); + } + await _fileUpdationDB.deleteByLocalIDs( + generatedIDs, + FileUpdationDB.badCreationTime, + ); + } catch (e) { + _logger.severe("Failed to fix bad creationTime", e); + } + } + + Future _importFilesWithBadCreationTime() async { + if (_prefs.containsKey(isBadCreationTimeImportDone) || + !Platform.isAndroid) { + return; + } + _logger.info('_importFilesWithBadCreationTime'); + final EnteWatch watch = EnteWatch("_importFilesWithBadCreationTime"); + final int ownerID = Configuration.instance.getUserID(); + final filesGeneratedID = await FilesDB.instance + .getGeneratedIDForFilesOlderThan(jan011981Time, ownerID); + await _fileUpdationDB.insertMultiple( + filesGeneratedID, + FileUpdationDB.badCreationTime, + ); + watch.log("imported ${filesGeneratedID.length} files"); + _prefs.setBool(isBadCreationTimeImportDone, true); + } }