This commit is contained in:
Neeraj Gupta
2025-07-02 16:37:06 +05:30
parent 6397ab888a
commit f32ea85ee2
4 changed files with 101 additions and 91 deletions

View File

@@ -134,86 +134,7 @@ class EnteFile {
return AssetEntity.fromId(localID!);
}
Future<Map<String, dynamic>> 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 = <String, dynamic>{};
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);

View File

@@ -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<String, IfdTag>? exifData = await tryExifFromFile(sourceFile);
final int? mviIndex = asset.type != AssetType.image
? null

View File

@@ -705,17 +705,12 @@ class FileUploader {
null,
mediaUploadData.exifData,
);
final metadata =
await file.getMetadataForUpload(mediaUploadData, exifTime);
final Map<String, dynamic> metadata =
await getMetadata(mediaUploadData, exifTime, file);
final Map<String, dynamic> 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();
}

View File

@@ -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<MediaUploadData> _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<void> _decorateEnteFileData(
Map<String, IfdTag>? 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<void> _decorateEnteFileData(
}
}
Future<Map<String, dynamic>> 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 = <String, dynamic>{};
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<MetadataRequest> getPubMetadataRequest(
EnteFile file,
Map<String, dynamic> jsonToUpdate,