Use the EXIF data provided by Nextcloud Photos

This commit is contained in:
Corentin Noël 2024-11-03 08:25:39 +00:00 committed by ming
parent d24e595d8f
commit 774bcd97c5
6 changed files with 42 additions and 2 deletions

View file

@ -50,7 +50,7 @@ class ApiFavoriteConverter {
class ApiFileConverter { class ApiFileConverter {
static File fromApi(api.File file) { static File fromApi(api.File file) {
final metadata = file.customProperties?["com.nkming.nc_photos:metadata"] var metadata = file.customProperties?["com.nkming.nc_photos:metadata"]
?.run((obj) => Metadata.fromJson( ?.run((obj) => Metadata.fromJson(
jsonDecode(obj), jsonDecode(obj),
upgraderV1: MetadataUpgraderV1( upgraderV1: MetadataUpgraderV1(
@ -66,6 +66,15 @@ class ApiFileConverter {
logFilePath: file.href, logFilePath: file.href,
), ),
)); ));
if (file.metadataPhotosIfd0 != null) {
final ifd0_metadata = Metadata.fromPhotosIfd0(file.metadataPhotosIfd0!);
if (metadata == null) {
metadata = ifd0_metadata;
} else {
metadata = metadata.copyWith(exif: ifd0_metadata.exif);
}
}
return File( return File(
path: _hrefToPath(file.href), path: _hrefToPath(file.href),
contentLength: file.contentLength, contentLength: file.contentLength,

View file

@ -185,6 +185,16 @@ class Metadata with EquatableMixin {
); );
} }
static Metadata fromPhotosIfd0(Map<String, String> metadataPhotosIfd0) {
return Metadata(
lastUpdated: null,
fileEtag: null,
imageWidth: null,
imageHeight: null,
exif: new Exif(metadataPhotosIfd0),
);
}
@override @override
String toString() => _$toString(); String toString() => _$toString();

View file

@ -55,6 +55,7 @@ class FileWebdavDataSource implements FileDataSource {
trashbinFilename: 1, trashbinFilename: 1,
trashbinOriginalLocation: 1, trashbinOriginalLocation: 1,
trashbinDeletionTime: 1, trashbinDeletionTime: 1,
metadataPhotosIfd0: 1,
customNamespaces: { customNamespaces: {
"com.nkming.nc_photos": "app", "com.nkming.nc_photos": "app",
}, },
@ -275,6 +276,7 @@ class FileWebdavDataSource implements FileDataSource {
trashbinFilename, trashbinFilename,
trashbinOriginalLocation, trashbinOriginalLocation,
trashbinDeletionTime, trashbinDeletionTime,
metadataPhotosIfd0,
Map<String, String>? customNamespaces, Map<String, String>? customNamespaces,
List<String>? customProperties, List<String>? customProperties,
}) async { }) async {
@ -302,6 +304,7 @@ class FileWebdavDataSource implements FileDataSource {
trashbinFilename: trashbinFilename, trashbinFilename: trashbinFilename,
trashbinOriginalLocation: trashbinOriginalLocation, trashbinOriginalLocation: trashbinOriginalLocation,
trashbinDeletionTime: trashbinDeletionTime, trashbinDeletionTime: trashbinDeletionTime,
metadataPhotosIfd0: metadataPhotosIfd0,
customNamespaces: customNamespaces, customNamespaces: customNamespaces,
customProperties: customProperties, customProperties: customProperties,
); );

View file

@ -84,6 +84,7 @@ class File with EquatableMixin {
this.trashbinFilename, this.trashbinFilename,
this.trashbinOriginalLocation, this.trashbinOriginalLocation,
this.trashbinDeletionTime, this.trashbinDeletionTime,
this.metadataPhotosIfd0,
this.customProperties, this.customProperties,
}); });
@ -106,6 +107,7 @@ class File with EquatableMixin {
trashbinFilename, trashbinFilename,
trashbinOriginalLocation, trashbinOriginalLocation,
trashbinDeletionTime, trashbinDeletionTime,
metadataPhotosIfd0,
customProperties, customProperties,
]; ];
@ -123,6 +125,7 @@ class File with EquatableMixin {
final String? trashbinFilename; final String? trashbinFilename;
final String? trashbinOriginalLocation; final String? trashbinOriginalLocation;
final DateTime? trashbinDeletionTime; final DateTime? trashbinDeletionTime;
final Map<String, String>? metadataPhotosIfd0;
final Map<String, String>? customProperties; final Map<String, String>? customProperties;
} }

View file

@ -33,6 +33,7 @@ class FileParser extends XmlResponseParser {
String? trashbinFilename; String? trashbinFilename;
String? trashbinOriginalLocation; String? trashbinOriginalLocation;
DateTime? trashbinDeletionTime; DateTime? trashbinDeletionTime;
Map<String, String>? metadataPhotosIfd0;
Map<String, String>? customProperties; Map<String, String>? customProperties;
for (final child in element.children.whereType<XmlElement>()) { for (final child in element.children.whereType<XmlElement>()) {
@ -66,6 +67,7 @@ class FileParser extends XmlResponseParser {
trashbinFilename = propParser.trashbinFilename; trashbinFilename = propParser.trashbinFilename;
trashbinOriginalLocation = propParser.trashbinOriginalLocation; trashbinOriginalLocation = propParser.trashbinOriginalLocation;
trashbinDeletionTime = propParser.trashbinDeletionTime; trashbinDeletionTime = propParser.trashbinDeletionTime;
metadataPhotosIfd0 = propParser.metadataPhotosIfd0;
customProperties = propParser.customProperties; customProperties = propParser.customProperties;
} }
} }
@ -85,6 +87,7 @@ class FileParser extends XmlResponseParser {
trashbinFilename: trashbinFilename, trashbinFilename: trashbinFilename,
trashbinOriginalLocation: trashbinOriginalLocation, trashbinOriginalLocation: trashbinOriginalLocation,
trashbinDeletionTime: trashbinDeletionTime, trashbinDeletionTime: trashbinDeletionTime,
metadataPhotosIfd0: metadataPhotosIfd0,
customProperties: customProperties, customProperties: customProperties,
); );
} }
@ -140,6 +143,11 @@ class _PropParser {
prefix: "http://nextcloud.org/ns", namespaces: namespaces)) { prefix: "http://nextcloud.org/ns", namespaces: namespaces)) {
_trashbinDeletionTime = DateTime.fromMillisecondsSinceEpoch( _trashbinDeletionTime = DateTime.fromMillisecondsSinceEpoch(
int.parse(child.innerText) * 1000); int.parse(child.innerText) * 1000);
} else if (child.matchQualifiedName("metadata-photos-ifd0",
prefix: "http://nextcloud.org/ns", namespaces: namespaces)) {
for (final ifd0_child in child.children.whereType<XmlElement>()) {
(_metadataPhotosIfd0 ??= {})[ifd0_child.name.toString()] = ifd0_child.innerText;
}
} else { } else {
final key = child.name.prefix == null final key = child.name.prefix == null
? child.localName ? child.localName
@ -162,6 +170,7 @@ class _PropParser {
String? get trashbinFilename => _trashbinFilename; String? get trashbinFilename => _trashbinFilename;
String? get trashbinOriginalLocation => _trashbinOriginalLocation; String? get trashbinOriginalLocation => _trashbinOriginalLocation;
DateTime? get trashbinDeletionTime => _trashbinDeletionTime; DateTime? get trashbinDeletionTime => _trashbinDeletionTime;
Map<String, String>? get metadataPhotosIfd0 => _metadataPhotosIfd0;
Map<String, String>? get customProperties => _customProperties; Map<String, String>? get customProperties => _customProperties;
final Map<String, String> namespaces; final Map<String, String> namespaces;
@ -179,6 +188,7 @@ class _PropParser {
String? _trashbinFilename; String? _trashbinFilename;
String? _trashbinOriginalLocation; String? _trashbinOriginalLocation;
DateTime? _trashbinDeletionTime; DateTime? _trashbinDeletionTime;
Map<String, String>? _metadataPhotosIfd0;
Map<String, String>? _customProperties; Map<String, String>? _customProperties;
} }

View file

@ -72,6 +72,7 @@ class ApiFiles {
trashbinFilename, trashbinFilename,
trashbinOriginalLocation, trashbinOriginalLocation,
trashbinDeletionTime, trashbinDeletionTime,
metadataPhotosIfd0,
Map<String, String>? customNamespaces, Map<String, String>? customNamespaces,
List<String>? customProperties, List<String>? customProperties,
}) async { }) async {
@ -96,7 +97,8 @@ class ApiFiles {
richWorkspace != null || richWorkspace != null ||
trashbinFilename != null || trashbinFilename != null ||
trashbinOriginalLocation != null || trashbinOriginalLocation != null ||
trashbinDeletionTime != null); trashbinDeletionTime != null ||
metadataPhotosIfd0 != null);
if (!hasDavNs && !hasOcNs && !hasNcNs) { if (!hasDavNs && !hasOcNs && !hasNcNs) {
// no body // no body
return await _api.request("PROPFIND", path); return await _api.request("PROPFIND", path);
@ -175,6 +177,9 @@ class ApiFiles {
if (trashbinDeletionTime != null) { if (trashbinDeletionTime != null) {
builder.element("nc:trashbin-deletion-time"); builder.element("nc:trashbin-deletion-time");
} }
if (metadataPhotosIfd0 != null) {
builder.element("nc:metadata-photos-ifd0");
}
for (final p in customProperties ?? []) { for (final p in customProperties ?? []) {
builder.element(p); builder.element(p);
} }