diff --git a/mobile/lib/models/file/file.dart b/mobile/lib/models/file/file.dart index d73dafd150..c5ecba8f3c 100644 --- a/mobile/lib/models/file/file.dart +++ b/mobile/lib/models/file/file.dart @@ -134,86 +134,7 @@ class EnteFile { return AssetEntity.fromId(localID!); } - Future> getMetadataForUpload( - MediaUploadData mediaUploadData, - ParsedExifDateTime? exifTime, - ) async { - final asset = await getAsset; - // asset can be null for files shared to app - if (asset != null) { - if (asset.type == AssetType.video) { - duration = asset.duration; - } - } - bool hasExifTime = false; - if (exifTime != null && exifTime.time != null) { - hasExifTime = true; - creationTime = exifTime.time!.microsecondsSinceEpoch; - } - if (mediaUploadData.exifData != null) { - mediaUploadData.isPanorama = - checkPanoramaFromEXIF(null, mediaUploadData.exifData); - } - if (mediaUploadData.isPanorama != true && - fileType == FileType.image && - mediaUploadData.sourceFile != null) { - try { - final xmpData = await getXmp(mediaUploadData.sourceFile!); - mediaUploadData.isPanorama = checkPanoramaFromXMP(xmpData); - } catch (_) {} - mediaUploadData.isPanorama ??= false; - } - - // Try to get the timestamp from fileName. In case of iOS, file names are - // generic IMG_XXXX, so only parse it on Android devices - if (!hasExifTime && Platform.isAndroid && title != null) { - final timeFromFileName = parseDateTimeFromName(title!); - if (timeFromFileName != null) { - // only use timeFromFileName if the existing creationTime and - // timeFromFilename belongs to different date. - // This is done because many times the fileTimeStamp will only give us - // the date, not time value but the photo_manager's creation time will - // contain the time. - final bool useFileTimeStamp = creationTime == null || - !areFromSameDay( - creationTime!, - timeFromFileName.microsecondsSinceEpoch, - ); - if (useFileTimeStamp) { - creationTime = timeFromFileName.microsecondsSinceEpoch; - } - } - } - - final metadata = {}; - metadata["localID"] = asset?.id; - final String? hashValue = mediaUploadData.hashData?.fileHash; - if (hashValue != null) { - metadata["hash"] = hashValue; - } - if (asset != null) { - metadata["subType"] = asset.subtype; - } - metadata["version"] = kCurrentMetadataVersion; - - metadata["title"] = title; - metadata["deviceFolder"] = deviceFolder; - metadata["creationTime"] = creationTime; - metadata["modificationTime"] = modificationTime; - metadata["fileType"] = fileType.index; - if (location != null && - location!.latitude != null && - location!.longitude != null) { - metadata["latitude"] = location!.latitude; - metadata["longitude"] = location!.longitude; - } - - if (duration != null) { - metadata["duration"] = duration; - } - - return metadata; - } + String get downloadUrl => FileUrl.getUrl(uploadedFileID!, FileUrlType.download); diff --git a/mobile/lib/services/local/metadata/metadata.service.dart b/mobile/lib/services/local/metadata/metadata.service.dart index 5eb3747420..46f31aa23f 100644 --- a/mobile/lib/services/local/metadata/metadata.service.dart +++ b/mobile/lib/services/local/metadata/metadata.service.dart @@ -8,7 +8,6 @@ import "package:logging/logging.dart"; import "package:motion_photos/motion_photos.dart"; import "package:photos/extensions/stop_watch.dart"; import "package:photos/models/ffmpeg/ffprobe_props.dart"; -import "package:photos/models/file/file.dart"; import "package:photos/models/local/local_metadata.dart"; import "package:photos/models/location/location.dart"; import "package:photos/services/local/asset_entity.service.dart"; @@ -28,7 +27,7 @@ class LocalMetadataService { final latLng = await asset.latlngAsync(); Location location = Location(latitude: latLng.latitude, longitude: latLng.longitude); - final int size = await sourceFile.length(); + final int size = sourceFile.lengthSync(); final Map? exifData = await tryExifFromFile(sourceFile); final int? mviIndex = asset.type != AssetType.image ? null diff --git a/mobile/lib/utils/file_uploader.dart b/mobile/lib/utils/file_uploader.dart index 65e22cd3f5..609f633d0f 100644 --- a/mobile/lib/utils/file_uploader.dart +++ b/mobile/lib/utils/file_uploader.dart @@ -705,17 +705,12 @@ class FileUploader { null, mediaUploadData.exifData, ); - final metadata = - await file.getMetadataForUpload(mediaUploadData, exifTime); + final Map metadata = + await getMetadata(mediaUploadData, exifTime, file); final Map pubMetadata = _buildPublicMagicData(mediaUploadData, exifTime, file.rAsset); MetadataRequest? pubMetadataRequest; - final fileDecryptionHeader = - CryptoUtil.bin2base64(fileEncryptResult.header!); - final thumbnailDecryptionHeader = - CryptoUtil.bin2base64(thumbEncResult.header!); - final encryptedMetadataResult = await CryptoUtil.encryptChaCha( utf8.encode(jsonEncode(metadata)), fileEncryptResult.key!, @@ -733,6 +728,10 @@ class FileUploader { fileEncryptResult.key!, ); } + final fileDecryptionHeader = + CryptoUtil.bin2base64(fileEncryptResult.header!); + final thumbnailDecryptionHeader = + CryptoUtil.bin2base64(thumbEncResult.header!); if (SyncService.instance.shouldStopSync()) { throw SyncStopRequestedError(); } diff --git a/mobile/lib/utils/upload_metadata.dart b/mobile/lib/utils/upload_metadata.dart index 29c714ec11..d3861b5ddd 100644 --- a/mobile/lib/utils/upload_metadata.dart +++ b/mobile/lib/utils/upload_metadata.dart @@ -26,6 +26,8 @@ import "package:photos/services/local/import/local_import.dart"; import "package:photos/services/local/livephoto.dart"; import "package:photos/services/local/shared_assert.service.dart"; import "package:photos/utils/exif_util.dart"; +import "package:photos/utils/panorama_util.dart"; +import "package:photos/utils/standalone/date_time.dart"; import "package:photos/utils/standalone/decode_image.dart"; import 'package:video_thumbnail/video_thumbnail.dart'; @@ -80,6 +82,7 @@ Future _getMediaUploadDataFromAssetFile( _logger.severe('error while detecthing motion photo start index', e); } } + fileHash = CryptoUtil.bin2base64(await CryptoUtil.getHash(sourceFile)); if (file.fileType == FileType.livePhoto && Platform.isIOS) { final (videoUrl, videoHash) = @@ -124,8 +127,7 @@ Future _decorateEnteFileData( Map? exifData, ) async { // h4ck to fetch location data if missing (thank you Android Q+) lazily only during uploads - if (file.location == null || - (file.location!.latitude == 0 && file.location!.longitude == 0)) { + if (!file.hasLocation) { final latLong = await asset.latlngAsync(); file.location = Location(latitude: latLong.latitude, longitude: latLong.longitude); @@ -149,6 +151,95 @@ Future _decorateEnteFileData( } } +Future> getMetadata( + MediaUploadData mediaUploadData, + ParsedExifDateTime? exifTime, + EnteFile file, +) async { + final AssetEntity? asset = await file.getAsset; + int? duration; + int? creationTime = file.creationTime; + final FileType fileType = file.fileType; + final String? title = file.title; + final String? deviceFolder = file.deviceFolder; + final int? modificationTime = file.modificationTime; + final Location? location = file.location; + // asset can be null for files shared to app + if (asset != null) { + if (asset.type == AssetType.video) { + duration = asset.duration; + } + } + bool hasExifTime = false; + if (exifTime != null && exifTime.time != null) { + hasExifTime = true; + creationTime = exifTime.time!.microsecondsSinceEpoch; + } + if (mediaUploadData.exifData != null) { + mediaUploadData.isPanorama = + checkPanoramaFromEXIF(null, mediaUploadData.exifData); + } + if (mediaUploadData.isPanorama != true && + fileType == FileType.image && + mediaUploadData.sourceFile != null) { + try { + final xmpData = await getXmp(mediaUploadData.sourceFile!); + mediaUploadData.isPanorama = checkPanoramaFromXMP(xmpData); + } catch (_) {} + mediaUploadData.isPanorama ??= false; + } + + // Try to get the timestamp from fileName. In case of iOS, file names are + // generic IMG_XXXX, so only parse it on Android devices + if (!hasExifTime && Platform.isAndroid && title != null) { + final timeFromFileName = parseDateTimeFromName(title); + if (timeFromFileName != null) { + // only use timeFromFileName if the existing creationTime and + // timeFromFilename belongs to different date. + // This is done because many times the fileTimeStamp will only give us + // the date, not time value but the photo_manager's creation time will + // contain the time. + final bool useFileTimeStamp = creationTime == null || + !areFromSameDay( + creationTime!, + timeFromFileName.microsecondsSinceEpoch, + ); + if (useFileTimeStamp) { + creationTime = timeFromFileName.microsecondsSinceEpoch; + } + } + } + + final metadata = {}; + metadata["localID"] = asset?.id; + final String? hashValue = mediaUploadData.hashData?.fileHash; + if (hashValue != null) { + metadata["hash"] = hashValue; + } + if (asset != null) { + metadata["subType"] = asset.subtype; + } + metadata["version"] = EnteFile.kCurrentMetadataVersion; + metadata["title"] = title; + metadata["deviceFolder"] = deviceFolder; + metadata["creationTime"] = creationTime; + metadata["modificationTime"] = modificationTime; + metadata["fileType"] = fileType.index; + if (location != null && + location.latitude != null && + location.longitude != null && + (location.latitude != 0 && location.longitude != 0)) { + metadata["latitude"] = location.latitude; + metadata["longitude"] = location.longitude; + } + + if (duration != null) { + metadata["duration"] = duration; + } + + return metadata; +} + Future getPubMetadataRequest( EnteFile file, Map jsonToUpdate,