用Python获取和设置Mac文件和文件夹Finder标签

12

我一直在尝试查找如何从Python中获取和设置文件标签的颜色。

我发现的最接近解决方案是这个,但我似乎找不到任何地方有macfile模块。难道我没有找到吗?

如果没有,还有其他方法可以实现吗?

5个回答

14
你可以使用xattr模块在Python中完成此操作。
这里有一个例子,大部分内容来自于这个问题
from xattr import xattr

colornames = {
    0: 'none',
    1: 'gray',
    2: 'green',
    3: 'purple',
    4: 'blue',
    5: 'yellow',
    6: 'red',
    7: 'orange',
}

attrs = xattr('./test.cpp')

try:
    finder_attrs = attrs['com.apple.FinderInfo']
    color = finder_attrs[9] >> 1 & 7
except KeyError:
    color = 0

print colornames[color]

自从我用红色标签给这个文件上了色,它会为我打印出'red'。你可以使用xattr模块将一个新的标签写回磁盘。

你知道这种方式是否也可以设置颜色吗?编辑:嗯,我刚试了一下,这对文件夹不起作用。可能需要找其他方法。 - GP89
这只能获取最后一个颜色集(在Mavericks中),你知道是否可能获取所有颜色以及相关的标签名称吗? - gotson
抱歉,我没有Mavericks。 - jterrace
此功能不支持具有多个标签的文件。 - dawg

5

如果你按照favoretti提供的链接往下滚动一点,会看到一个指向https://github.com/danthedeckie/display_colors 的链接,它使用 xattr 来实现此功能,但没有进行二进制操作。我对他的代码进行了一些修改:

from xattr import xattr

def set_label(filename, color_name):
    colors = ['none', 'gray', 'green', 'purple', 'blue', 'yellow', 'red', 'orange']
    key = u'com.apple.FinderInfo'
    attrs = xattr(filename)
    current = attrs.copy().get(key, chr(0)*32)
    changed = current[:9] + chr(colors.index(color_name)*2) + current[10:]
    attrs.set(key, changed)

set_label('/Users/chbrown/Desktop', 'green')

4

我不知道这个问题是否仍然与任何人有关,但有一个名为“mac-tag”的新包可以解决此问题。

pip install mac-tag

然后你还有像这样的函数:

function    __doc__
mac_tag.add(tags, path) # add tags to path(s)
mac_tag.find(tags, path=None)   # return a list of all paths with tags, limited to path(s) if present
mac_tag.get(path)   # return dict where keys are paths, values are lists of tags. equivalent of tag -l
mac_tag.match(tags, path)   # return a list of paths with with matching tags
mac_tag.parse_list_output(out)  # parse tag -l output and return dict
mac_tag.remove(tags, path)  # remove tags from path(s)
mac_tag.update(tags, path)  # set path(s) tags. equivalent of `tag -s

完整文档请参阅:https://pypi.org/project/mac-tag/

谢谢!这就是我在寻找的东西 :) - ideaguy3d

0
假设您有这个文件夹:

enter image description here

请注意,一些文件有多个标签。其中一个标签是自定义标签Work
我使用了三种方法将Finder标签导入Python。

首先,使用xattr从键'com.apple.metadata:_kMDItemUserTags'生成扩展属性的二进制plist,然后使用plistlib将其转换为列表:

import xattr
import plistlib 

def get_tags_xattr(fn):
    try:
        bpl=xattr.getxattr(fn, 'com.apple.metadata:_kMDItemUserTags')
        rtr=[e.partition('\n')[0] 
                  for e in plistlib.loads(bpl, fmt=plistlib.FMT_BINARY)]
        return rtr if rtr else None
    
    except OSError:
        return None 

第二种方法是使用可以通过brew安装的程序tag
from subprocess import run, PIPE

def get_tags_tag(fn):
    if 'com.apple.metadata:_kMDItemUserTags' in xattr.listxattr(fn):
        rtr=run(['tag', '-g', '--no-name', fn], 
            stdout=PIPE).stdout.decode('utf-8').splitlines()
        return rtr if rtr else None
    
    return None 

第三种方法是使用PyPi模块osxmetadata
import osxmetadata

def get_tags_osxmeta(fn):
    tags=[t.name for t in osxmetadata.OSXMetaData(fn).tags]
    if tags:
        return tags 
    
    return None 

以下是三个示例的演示:

from pathlib import Path 

p=Path('/tmp/test')

for fn in (fn for fn in p.glob('*') if fn.is_file()):
    print(fn, get_tags_osxmeta(fn), 
          get_tags_tag(fn), 
          get_tags_xattr(fn))   

打印在该示例文件夹上:

/tmp/test/DSC_2930-m.jpg ['Red', 'Green'] ['Green', 'Red'] ['Red', 'Green']
/tmp/test/DSC_2929.JPG None None None
/tmp/test/DSC_2939.JPG None None None
/tmp/test/DSC_2938.JPG ['Red'] ['Red'] ['Red']
/tmp/test/DSC_2937.JPG None None None
/tmp/test/DSC_2942-m.jpg ['Red', 'Orange', 'Gray', 'Work'] ['Gray', 'Orange', 'Red', 'Work'] ['Red', 'Orange', 'Gray', 'Work']
/tmp/test/DSC_2934.JPG ['Red'] ['Red'] ['Red']
/tmp/test/DSC_2930.JPG None None None
/tmp/test/DSC_2931.JPG None None None
/tmp/test/DSC_2933.JPG None None None
/tmp/test/DSC_2932.JPG ['Red'] ['Red'] ['Red']
/tmp/test/DSC_2941.JPG None None None
/tmp/test/DSC_2942.JPG None None None

其中最好的(我经常使用的)是osxmetadata模块。它快速而且非常灵活。如果你只需要标签,其他方法也可以很好地工作。第一个可能是最快的。


0

macfile 模块是 appscript 模块的一部分,自 "2006-11-20 -- 0.2.0" 起更名为 mactypes

使用此模块,以下是两个用于获取和设置 appscript 版本 1.0 中查找器标签的函数:

from appscript import app
from mactypes import File as MacFile


# Note these label names could be changed in the Finder preferences,
# but the colours are fixed
FINDER_LABEL_NAMES = {
    0: 'none',
    1: 'orange',
    2: 'red',
    3: 'yellow',
    4: 'blue',
    5: 'purple',
    6: 'green',
    7: 'gray',
}


def finder_label(path):
    """Get the Finder label colour for the given path

    >>> finder_label("/tmp/example.txt")
    'green'
    """
    idx = app('Finder').items[MacFile(path)].label_index.get()
    return FINDER_LABEL_NAMES[idx]


def set_finder_label(path, label):
    """Set the Finder label by colour

    >>> set_finder_label("/tmp/example.txt", "blue")
    """

    label_rev = {v:k for k, v in FINDER_LABEL_NAMES.items()}

    available = label_rev.keys()
    if label not in available:
        raise ValueError(
            "%r not in available labels of %s" % (
                label,
                ", ".join(available)))

    app('Finder').items[MacFile(path)].label_index.set(label_rev[label])

if __name__ == "__main__":
    # Touch file
    path = "blah"
    open(path, "w").close()

    # Toggle label colour
    if finder_label(path) == "green":
        set_finder_label(path, "red")
    else:
        set_finder_label(path, "green")

至少在OSX 10.9.5中,文件似乎不再具有“label_index”。我多年来一直使用类似的代码,但是重新启动旧项目时,它不再起作用,而另一种方法却可以。 - Hraban

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接