#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
|
var foundXmp = false
|
||||||
|
|
||||||
fun processXmp(xmpMeta: XMPMeta) {
|
fun processXmp(xmpMeta: XMPMeta) {
|
||||||
offsetFromEnd = GoogleXMP.getTrailingVideoOffsetFromEnd(xmpMeta)
|
offsetFromEnd = offsetFromEnd ?: GoogleXMP.getTrailingVideoOffsetFromEnd(xmpMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -109,10 +109,11 @@ object GoogleXMP {
|
||||||
var hasImage = false
|
var hasImage = false
|
||||||
var hasVideo = false
|
var hasVideo = false
|
||||||
for (i in 1 until count + 1) {
|
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 mime = getContainerItemAttribute(meta, i, GCONTAINER_ITEM_MIME_PROP_NAME)
|
||||||
val length = meta.getSafeStructField(listOf(GCONTAINER_DIRECTORY_PROP_NAME, i, GCONTAINER_ITEM_PROP_NAME, GCONTAINER_ITEM_LENGTH_PROP_NAME))?.value
|
val length = getContainerItemAttribute(meta, i, GCONTAINER_ITEM_LENGTH_PROP_NAME)
|
||||||
hasImage = hasImage || MimeTypes.isImage(mime) && length != null
|
// `length` is not always provided for the image item
|
||||||
hasVideo = hasVideo || MimeTypes.isVideo(mime) && length != null
|
hasImage = hasImage || MimeTypes.isImage(mime)
|
||||||
|
hasVideo = hasVideo || (MimeTypes.isVideo(mime) && length != null)
|
||||||
}
|
}
|
||||||
if (hasImage && hasVideo) return true
|
if (hasImage && hasVideo) return true
|
||||||
}
|
}
|
||||||
|
@ -128,6 +129,13 @@ object GoogleXMP {
|
||||||
return false
|
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 {
|
fun isPanorama(meta: XMPMeta): Boolean {
|
||||||
try {
|
try {
|
||||||
if (gpanoRequiredProps.all { meta.doesPropExist(it) }) return true
|
if (gpanoRequiredProps.all { meta.doesPropExist(it) }) return true
|
||||||
|
@ -166,10 +174,9 @@ object GoogleXMP {
|
||||||
// `Container` motion photo
|
// `Container` motion photo
|
||||||
val count = meta.countPropArrayItems(GCONTAINER_DIRECTORY_PROP_NAME)
|
val count = meta.countPropArrayItems(GCONTAINER_DIRECTORY_PROP_NAME)
|
||||||
for (i in 1 until count + 1) {
|
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 mime = getContainerItemAttribute(meta, i, GCONTAINER_ITEM_MIME_PROP_NAME)
|
||||||
val length = meta.getSafeStructField(listOf(GCONTAINER_DIRECTORY_PROP_NAME, i, GCONTAINER_ITEM_PROP_NAME, GCONTAINER_ITEM_LENGTH_PROP_NAME))?.value
|
if (MimeTypes.isVideo(mime)) {
|
||||||
if (MimeTypes.isVideo(mime) && length != null) {
|
getContainerItemAttribute(meta, i, GCONTAINER_ITEM_LENGTH_PROP_NAME)?.let { offsetFromEnd = it.toLong() }
|
||||||
offsetFromEnd = length.toLong()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ class XmpNamespaces {
|
||||||
static const gAudio = 'http://ns.google.com/photos/1.0/audio/';
|
static const gAudio = 'http://ns.google.com/photos/1.0/audio/';
|
||||||
static const gCamera = 'http://ns.google.com/photos/1.0/camera/';
|
static const gCamera = 'http://ns.google.com/photos/1.0/camera/';
|
||||||
static const gContainer = 'http://ns.google.com/photos/1.0/container/';
|
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 gCreations = 'http://ns.google.com/photos/1.0/creations/';
|
||||||
static const gDepth = 'http://ns.google.com/photos/1.0/depthmap/';
|
static const gDepth = 'http://ns.google.com/photos/1.0/depthmap/';
|
||||||
static const gDevice = 'http://ns.google.com/photos/dd/1.0/device/';
|
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) {
|
List<Widget> buildNamespaceSection(BuildContext context) {
|
||||||
final props = rawProps.entries
|
final props = rawProps.entries
|
||||||
.map((kv) {
|
.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;
|
var extracted = false;
|
||||||
cards.forEach((card) => extracted |= card.extract(prop));
|
cards.forEach((card) => extracted |= card.extract(prop));
|
||||||
return extracted ? null : prop;
|
return extracted ? null : prop;
|
||||||
|
@ -134,6 +138,8 @@ class XmpNamespace extends Equatable {
|
||||||
: [];
|
: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<RegExp> get skippedProps => {};
|
||||||
|
|
||||||
List<XmpCardData> get cards => [];
|
List<XmpCardData> get cards => [];
|
||||||
|
|
||||||
String formatValue(XmpProp prop) => prop.value;
|
String formatValue(XmpProp prop) => prop.value;
|
||||||
|
|
|
@ -73,11 +73,26 @@ class XmpGCameraNamespace extends XmpGoogleNamespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
class XmpGContainer extends XmpNamespace {
|
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
|
@override
|
||||||
late final List<XmpCardData> cards = [
|
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'),
|
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