Run reverse geocoding in metadata task

This commit is contained in:
Ming Ming 2022-08-27 23:32:31 +08:00
parent 189f536f29
commit 8e1aeaa013
4 changed files with 73 additions and 28 deletions

View file

@ -88,8 +88,11 @@ bool isNoMediaMarkerPath(String path) {
} }
/// Return if there's missing metadata in [file] /// Return if there's missing metadata in [file]
///
/// Current this function will check both [File.metadata] and [File.location]
bool isMissingMetadata(File file) => bool isMissingMetadata(File file) =>
isSupportedImageFormat(file) && file.metadata == null; isSupportedImageFormat(file) &&
(file.metadata == null || file.location == null);
final _supportedFormatMimes = [ final _supportedFormatMimes = [
"image/jpeg", "image/jpeg",

View file

@ -9,6 +9,7 @@ import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref.dart';
import 'package:nc_photos/reverse_geocoder.dart';
import 'package:nc_photos/use_case/update_missing_metadata.dart'; import 'package:nc_photos/use_case/update_missing_metadata.dart';
/// Task to update metadata for missing files /// Task to update metadata for missing files
@ -29,11 +30,13 @@ class MetadataTask {
final shareFolder = final shareFolder =
File(path: file_util.unstripPath(account, pref.getShareFolderOr())); File(path: file_util.unstripPath(account, pref.getShareFolderOr()));
bool hasScanShareFolder = false; bool hasScanShareFolder = false;
final geocoder = ReverseGeocoder();
await geocoder.init();
for (final r in account.roots) { for (final r in account.roots) {
final dir = File(path: file_util.unstripPath(account, r)); final dir = File(path: file_util.unstripPath(account, r));
hasScanShareFolder |= file_util.isOrUnderDir(shareFolder, dir); hasScanShareFolder |= file_util.isOrUnderDir(shareFolder, dir);
final op = UpdateMissingMetadata( final op = UpdateMissingMetadata(_c.fileRepo,
_c.fileRepo, const _UpdateMissingMetadataConfigProvider()); const _UpdateMissingMetadataConfigProvider(), geocoder);
await for (final _ in op(account, dir)) { await for (final _ in op(account, dir)) {
if (!Pref().isEnableExifOr()) { if (!Pref().isEnableExifOr()) {
_log.info("[call] EXIF disabled, task ending immaturely"); _log.info("[call] EXIF disabled, task ending immaturely");
@ -43,8 +46,8 @@ class MetadataTask {
} }
} }
if (!hasScanShareFolder) { if (!hasScanShareFolder) {
final op = UpdateMissingMetadata( final op = UpdateMissingMetadata(_c.fileRepo,
_c.fileRepo, const _UpdateMissingMetadataConfigProvider()); const _UpdateMissingMetadataConfigProvider(), geocoder);
await for (final _ in op( await for (final _ in op(
account, account,
shareFolder, shareFolder,

View file

@ -19,6 +19,7 @@ import 'package:nc_photos/event/native_event.dart';
import 'package:nc_photos/future_extension.dart'; import 'package:nc_photos/future_extension.dart';
import 'package:nc_photos/language_util.dart' as language_util; import 'package:nc_photos/language_util.dart' as language_util;
import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref.dart';
import 'package:nc_photos/reverse_geocoder.dart';
import 'package:nc_photos/use_case/update_missing_metadata.dart'; import 'package:nc_photos/use_case/update_missing_metadata.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart'; import 'package:nc_photos_plugin/nc_photos_plugin.dart';
@ -248,11 +249,13 @@ class _MetadataTask {
path: file_util.unstripPath(account, accountPref.getShareFolderOr())); path: file_util.unstripPath(account, accountPref.getShareFolderOr()));
bool hasScanShareFolder = false; bool hasScanShareFolder = false;
final c = KiwiContainer().resolve<DiContainer>(); final c = KiwiContainer().resolve<DiContainer>();
final geocoder = ReverseGeocoder();
await geocoder.init();
for (final r in account.roots) { for (final r in account.roots) {
final dir = File(path: file_util.unstripPath(account, r)); final dir = File(path: file_util.unstripPath(account, r));
hasScanShareFolder |= file_util.isOrUnderDir(shareFolder, dir); hasScanShareFolder |= file_util.isOrUnderDir(shareFolder, dir);
final updater = UpdateMissingMetadata( final updater = UpdateMissingMetadata(
c.fileRepo, const _UpdateMissingMetadataConfigProvider()); c.fileRepo, const _UpdateMissingMetadataConfigProvider(), geocoder);
void onServiceStop() { void onServiceStop() {
_log.info("[_updateMetadata] Stopping task: user canceled"); _log.info("[_updateMetadata] Stopping task: user canceled");
updater.stop(); updater.stop();
@ -275,7 +278,7 @@ class _MetadataTask {
} }
if (!hasScanShareFolder) { if (!hasScanShareFolder) {
final shareUpdater = UpdateMissingMetadata( final shareUpdater = UpdateMissingMetadata(
c.fileRepo, const _UpdateMissingMetadataConfigProvider()); c.fileRepo, const _UpdateMissingMetadataConfigProvider(), geocoder);
void onServiceStop() { void onServiceStop() {
_log.info("[_updateMetadata] Stopping task: user canceled"); _log.info("[_updateMetadata] Stopping task: user canceled");
shareUpdater.stop(); shareUpdater.stop();

View file

@ -4,11 +4,13 @@ import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/connectivity_util.dart' as connectivity_util; import 'package:nc_photos/connectivity_util.dart' as connectivity_util;
import 'package:nc_photos/entity/exif_extension.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/exception.dart'; import 'package:nc_photos/exception.dart';
import 'package:nc_photos/exception_event.dart'; import 'package:nc_photos/exception_event.dart';
import 'package:nc_photos/or_null.dart'; import 'package:nc_photos/or_null.dart';
import 'package:nc_photos/reverse_geocoder.dart';
import 'package:nc_photos/use_case/get_file_binary.dart'; import 'package:nc_photos/use_case/get_file_binary.dart';
import 'package:nc_photos/use_case/load_metadata.dart'; import 'package:nc_photos/use_case/load_metadata.dart';
import 'package:nc_photos/use_case/scan_missing_metadata.dart'; import 'package:nc_photos/use_case/scan_missing_metadata.dart';
@ -19,7 +21,7 @@ abstract class UpdateMissingMetadataConfigProvider {
} }
class UpdateMissingMetadata { class UpdateMissingMetadata {
UpdateMissingMetadata(this.fileRepo, this.configProvider); UpdateMissingMetadata(this.fileRepo, this.configProvider, this.geocoder);
/// Update metadata for all files that support one under a dir /// Update metadata for all files that support one under a dir
/// ///
@ -43,6 +45,9 @@ class UpdateMissingMetadata {
isRecursive: isRecursive, isRecursive: isRecursive,
); );
await for (final d in dataStream) { await for (final d in dataStream) {
if (!_shouldRun) {
return;
}
if (d is ExceptionEvent) { if (d is ExceptionEvent) {
yield d; yield d;
continue; continue;
@ -54,12 +59,16 @@ class UpdateMissingMetadata {
continue; continue;
} }
try { try {
OrNull<Metadata>? metadataUpdate;
OrNull<ImageLocation>? locationUpdate;
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 _ensureWifi(); await _ensureWifi();
await _ensureBattery(); await _ensureBattery();
KiwiContainer().resolve<EventBus>().fire( KiwiContainer().resolve<EventBus>().fire(
const MetadataTaskStateChangedEvent(MetadataTaskState.prcoessing)); const MetadataTaskStateChangedEvent(
MetadataTaskState.prcoessing));
if (!_shouldRun) { if (!_shouldRun) {
return; return;
} }
@ -69,13 +78,39 @@ class UpdateMissingMetadata {
(await LoadMetadata().loadRemote(account, file, binary)).copyWith( (await LoadMetadata().loadRemote(account, file, binary)).copyWith(
fileEtag: file.etag, fileEtag: file.etag,
); );
metadataUpdate = OrNull(metadata);
} else {
_log.finer("[call] Skip updating metadata for ${file.path}");
}
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("[call] Reverse geocoding for ${file.path}");
final l = await geocoder(lat, lng);
if (l != null) {
location = l.toImageLocation();
}
}
locationUpdate = OrNull(location ?? ImageLocation.empty());
} catch (e, stackTrace) {
_log.severe("[call] Failed while reverse geocoding: ${file.path}", e,
stackTrace);
}
if (metadataUpdate != null || locationUpdate != null) {
await UpdateProperty(fileRepo)( await UpdateProperty(fileRepo)(
account, account,
file, file,
metadata: OrNull(metadata), metadata: metadataUpdate,
location: locationUpdate,
); );
yield file; yield file;
}
// slow down a bit to give some space for the main isolate // slow down a bit to give some space for the main isolate
await Future.delayed(const Duration(milliseconds: 10)); await Future.delayed(const Duration(milliseconds: 10));
@ -123,6 +158,7 @@ class UpdateMissingMetadata {
final FileRepo fileRepo; final FileRepo fileRepo;
final UpdateMissingMetadataConfigProvider configProvider; final UpdateMissingMetadataConfigProvider configProvider;
final ReverseGeocoder geocoder;
bool _shouldRun = true; bool _shouldRun = true;