#894 fixed motion photo detection for xml variant of google container item
This commit is contained in:
parent
b4a5513fe1
commit
e57484d912
5 changed files with 40 additions and 11 deletions
|
@ -274,7 +274,7 @@ object MultiPage {
|
|||
var foundXmp = false
|
||||
|
||||
fun processXmp(xmpMeta: XMPMeta) {
|
||||
offsetFromEnd = GoogleXMP.getTrailingVideoOffsetFromEnd(xmpMeta)
|
||||
offsetFromEnd = offsetFromEnd ?: GoogleXMP.getTrailingVideoOffsetFromEnd(xmpMeta)
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -109,10 +109,11 @@ object GoogleXMP {
|
|||
var hasImage = false
|
||||
var hasVideo = false
|
||||
for (i in 1 until count + 1) {
|
||||
val mime = meta.getSafeStructField(listOf(GCONTAINER_DIRECTORY_PROP_NAME, i, GCONTAINER_ITEM_PROP_NAME, GCONTAINER_ITEM_MIME_PROP_NAME))?.value
|
||||
val length = meta.getSafeStructField(listOf(GCONTAINER_DIRECTORY_PROP_NAME, i, GCONTAINER_ITEM_PROP_NAME, GCONTAINER_ITEM_LENGTH_PROP_NAME))?.value
|
||||
hasImage = hasImage || MimeTypes.isImage(mime) && length != null
|
||||
hasVideo = hasVideo || MimeTypes.isVideo(mime) && length != null
|
||||
val mime = getContainerItemAttribute(meta, i, GCONTAINER_ITEM_MIME_PROP_NAME)
|
||||
val length = getContainerItemAttribute(meta, i, GCONTAINER_ITEM_LENGTH_PROP_NAME)
|
||||
// `length` is not always provided for the image item
|
||||
hasImage = hasImage || MimeTypes.isImage(mime)
|
||||
hasVideo = hasVideo || (MimeTypes.isVideo(mime) && length != null)
|
||||
}
|
||||
if (hasImage && hasVideo) return true
|
||||
}
|
||||
|
@ -128,6 +129,13 @@ object GoogleXMP {
|
|||
return false
|
||||
}
|
||||
|
||||
private fun getContainerItemAttribute(meta: XMPMeta, i: Int, attribute: XMPPropName): String? {
|
||||
// variant of `Container:Item` with `<rdf:li rdf:parseType="Resource">`
|
||||
val mime = meta.getSafeStructField(listOf(GCONTAINER_DIRECTORY_PROP_NAME, i, GCONTAINER_ITEM_PROP_NAME, attribute))?.value
|
||||
// variant of `Container:Item` with `<rdf:li>`
|
||||
return mime ?: meta.getSafeStructField(listOf(GCONTAINER_DIRECTORY_PROP_NAME, i, attribute))?.value
|
||||
}
|
||||
|
||||
fun isPanorama(meta: XMPMeta): Boolean {
|
||||
try {
|
||||
if (gpanoRequiredProps.all { meta.doesPropExist(it) }) return true
|
||||
|
@ -166,10 +174,9 @@ object GoogleXMP {
|
|||
// `Container` motion photo
|
||||
val count = meta.countPropArrayItems(GCONTAINER_DIRECTORY_PROP_NAME)
|
||||
for (i in 1 until count + 1) {
|
||||
val mime = meta.getSafeStructField(listOf(GCONTAINER_DIRECTORY_PROP_NAME, i, GCONTAINER_ITEM_PROP_NAME, GCONTAINER_ITEM_MIME_PROP_NAME))?.value
|
||||
val length = meta.getSafeStructField(listOf(GCONTAINER_DIRECTORY_PROP_NAME, i, GCONTAINER_ITEM_PROP_NAME, GCONTAINER_ITEM_LENGTH_PROP_NAME))?.value
|
||||
if (MimeTypes.isVideo(mime) && length != null) {
|
||||
offsetFromEnd = length.toLong()
|
||||
val mime = getContainerItemAttribute(meta, i, GCONTAINER_ITEM_MIME_PROP_NAME)
|
||||
if (MimeTypes.isVideo(mime)) {
|
||||
getContainerItemAttribute(meta, i, GCONTAINER_ITEM_LENGTH_PROP_NAME)?.let { offsetFromEnd = it.toLong() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ class XmpNamespaces {
|
|||
static const gAudio = 'http://ns.google.com/photos/1.0/audio/';
|
||||
static const gCamera = 'http://ns.google.com/photos/1.0/camera/';
|
||||
static const gContainer = 'http://ns.google.com/photos/1.0/container/';
|
||||
static const gContainerItem = 'http://ns.google.com/photos/1.0/container/item/';
|
||||
static const gCreations = 'http://ns.google.com/photos/1.0/creations/';
|
||||
static const gDepth = 'http://ns.google.com/photos/1.0/depthmap/';
|
||||
static const gDevice = 'http://ns.google.com/photos/dd/1.0/device/';
|
||||
|
|
|
@ -90,7 +90,11 @@ class XmpNamespace extends Equatable {
|
|||
List<Widget> buildNamespaceSection(BuildContext context) {
|
||||
final props = rawProps.entries
|
||||
.map((kv) {
|
||||
final prop = XmpProp(kv.key, kv.value);
|
||||
final key = kv.key;
|
||||
if (skippedProps.any((pattern) => pattern.allMatches(key).isNotEmpty)) {
|
||||
return null;
|
||||
}
|
||||
final prop = XmpProp(key, kv.value);
|
||||
var extracted = false;
|
||||
cards.forEach((card) => extracted |= card.extract(prop));
|
||||
return extracted ? null : prop;
|
||||
|
@ -134,6 +138,8 @@ class XmpNamespace extends Equatable {
|
|||
: [];
|
||||
}
|
||||
|
||||
Set<RegExp> get skippedProps => {};
|
||||
|
||||
List<XmpCardData> get cards => [];
|
||||
|
||||
String formatValue(XmpProp prop) => prop.value;
|
||||
|
|
|
@ -73,11 +73,26 @@ class XmpGCameraNamespace extends XmpGoogleNamespace {
|
|||
}
|
||||
|
||||
class XmpGContainer extends XmpNamespace {
|
||||
XmpGContainer({required super.schemaRegistryPrefixes, required super.rawProps}) : super(nsUri: XmpNamespaces.gContainer);
|
||||
late final String _gContainerItemNsPrefix;
|
||||
late final String _rdfNsPrefix;
|
||||
|
||||
XmpGContainer({required super.schemaRegistryPrefixes, required super.rawProps}) : super(nsUri: XmpNamespaces.gContainer) {
|
||||
_gContainerItemNsPrefix = XmpNamespace.prefixForUri(schemaRegistryPrefixes, XmpNamespaces.gContainerItem);
|
||||
_rdfNsPrefix = XmpNamespace.prefixForUri(schemaRegistryPrefixes, XmpNamespaces.rdf);
|
||||
}
|
||||
|
||||
@override
|
||||
late final Set<RegExp> skippedProps = {
|
||||
// variant of `Container:Item` with `<rdf:li>`
|
||||
RegExp(nsPrefix + r'Directory\[(\d+)\]/' + _rdfNsPrefix + r'type'),
|
||||
};
|
||||
|
||||
@override
|
||||
late final List<XmpCardData> cards = [
|
||||
// variant of `Container:Item` with `<rdf:li rdf:parseType="Resource">`
|
||||
XmpCardData(RegExp(nsPrefix + r'Directory\[(\d+)\]/' + nsPrefix + r'Item/(.*)'), title: 'Directory Item'),
|
||||
// variant of `Container:Item` with `<rdf:li>`
|
||||
XmpCardData(RegExp(nsPrefix + r'Directory\[(\d+)\]/(' + _gContainerItemNsPrefix + r'.*)'), title: 'Directory Item'),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue