Using multiple keywords in xattr via _kMDItemUserTags or kMDItemOMUserTags

2024/10/1 9:38:11

While reorganizing my images, in anticipation of OSX Mavericks I am writing a script to insert tags into the xattr fields of my image files, so I can search them with Spotlight. (I am also editing the EXIF just to be safe.)

My questions are:

  1. Which attribute is the best to use? _kMDItemUserTags seems to be the OSX version, but kMDItemOMUserTags is already in use by OpenMeta. I would ideally like something that will be Linux and OSX forward compatible.

  2. How do I set multiple tags? Are the comma- or space-delimited or something else?

As an example, using the python xattr module, I am issuing these commands:

xattr.setxattr(FileName, "_kMDItemUserTags", "Name - Sample")
xattr.setxattr(FileName, "kMDItemOMUserTags", "Name,Institution,Sample")

I have also seen mention of these tags: kOMUserTags and kMDItemkeywords but don't know if they are likely to be implemented...

EDIT: Further investigation has shown that for things to be searchable in 10.8,

  • You need to preface the kMD with com.apple.metadata:
  • You have to either hex-encode or wrap in a plist.

This python code will generate the tag for kMDItemFinderComment which is searchable in spotlight...

def writexattrs(F,TagList):""" writexattrs(F,TagList):writes the list of tags to three xattr field:'kMDItemFinderComment','_kMDItemUserTags','kMDItemOMUserTags'This version uses the xattr library """plistFront = '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><array>'plistEnd = '</array></plist>'plistTagString = ''for Tag in TagList:plistTagString = plistTagString + '<string>{}</string>'.format(Tag)TagText = plistFront + plistTagString + plistEndOptionalTag = "com.apple.metadata:"XattrList = ["kMDItemFinderComment","_kMDItemUserTags","kMDItemOMUserTags"]for Field in XattrList:xattr.setxattr (F,OptionalTag+Field,TagText.encode('utf8'))# Equivalent shell command is xattr -w com.apple.metadata:kMDItemFinderComment [PLIST value] [File name]

I could not get it to work recursively on a folder with reliable results.

Answer
  1. If you are worried about compatibility you have to set both of the attributes _kMDItemUserTags and kMDItemOMUserTags. I don't think there's a different solution since all the new OS X apps will use the former attribute, while the old apps still use the latter. This is just my speculation, but I guess OpenMeta will eventually be discontinued in favor of the new native API. Looking to the future you can use the _kMDItemUserTags attribute for your new apps/scripts even in Linux environment.

  2. The tags are set as a property list-encoded array of strings as you have figured out. I don't know if it is a requirement but the OS X encodes the property list in the binary format and not in XML as you did.

I adapted your code to use binary property list as attribute values and everything worked. Here's my code. I am using biplist library which you can get with easy_install biplist.

import xattr
import biplistdef write_xattr_tags(file_path, tags):bpl_tags = biplist.writePlistToString(tags)optional_tag = "com.apple.metadata:"map(lambda a: xattr.setxattr(file_path, optional_tag + a, bpl_tags),["kMDItemFinderComment", "_kMDItemUserTags", "kMDItemOMUserTags"])

Tested with files and directories using tag:<some_tag> in Spotlight.

Hope this helps.

  • Note: I am using OS X Lion in this answer but it should work on Mavericks without any problems.
  • Edit: If you want to apply the tags to the contents of a directory it has to be done individually for every file since the xattr python module doesn't have the recursive option.
https://en.xdnf.cn/q/70970.html

Related Q&A

JAX Apply function only on slice of array under jit

I am using JAX, and I want to perform an operation like @jax.jit def fun(x, index):x[:index] = other_fun(x[:index])return xThis cannot be performed under jit. Is there a way of doing this with jax.ops …

Using my own corpus for category classification in Python NLTK

Im a NTLK/Python beginner and managed to load my own corpus using CategorizedPlaintextCorpusReader but how do I actually train and use the data for classification of text?>>> from nltk.corpus…

Python ImportError for strptime in spyder for windows 7

I cant for the life of me figure out what is causing this very odd error.I am running a script in python 2.7 in the spyder IDE for windows 7. It uses datetime.datetime.strptime at one point. I can run …

How to show diff of two string sequences in colors?

Im trying to find a Python way to diff strings. I know about difflib but I havent been able to find an inline mode that does something similar to what this JS library does (insertions in green, deletio…

Regex for timestamp

Im terrible at regex apparently, it makes no sense to me...Id like an expression for matching a time, like 01:23:45 within a string. I tried this (r(([0-9]*2)[:])*2([0-9]*2)but its not working. I need …

os.read(0,) vs sys.stdin.buffer.read() in python

I encountered the picotui library, and was curious to know a bit how it works. I saw here (line 147) that it uses: os.read(0,32)According to Google 0 represents stdin, but also that the accepted answer…

python - Pandas: groupby ffill for multiple columns

I have the following DataFrame with some missing values. I want to use ffill() to fill missing values in both var1 and var2 grouped by date and building. I can do that for one variable at a time, but w…

Gtk-Message: Failed to load module canberra-gtk-module

My pygtk program writes this warning to stderr:Gtk-Message: Failed to load module "canberra-gtk-module"libcanberra seems to be a library for sound.My program does not use any sound. Is there …

Why does installation of some Python packages require Visual Studio?

Say, you are installing a Python package for pyEnchant or crfsuite, etc. It fails to install and in the error trace it says some .bat (or .dll) file is missing.A few forums suggest you install Visual S…

Does Django ORM have an equivalent to SQLAlchemys Hybrid Attribute?

In SQLAlchemy, a hybrid attribute is either a property or method applied to an ORM-mapped class,class Interval(Base):__tablename__ = intervalid = Column(Integer, primary_key=True)start = Column(Integer…