Last active
September 25, 2017 19:52
Manipulate and list the Finder tags on an MacOS file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require "ffi-xattr" | |
require "cfpropertylist" | |
require "pry" | |
class Tag | |
COLORS = { | |
white: 0, | |
gray: 1, | |
green: 2, | |
purple: 3, | |
blue: 4, | |
yellow: 5, | |
red: 6, | |
orange: 7 | |
}.freeze | |
INVERSE_COLORS = COLORS.values.zip(COLORS.keys).to_h.freeze | |
attr_accessor :name, :color | |
def initialize name:, color: :white | |
color = INVERSE_COLORS[ color ] if color.is_a? Numeric | |
fail ArgumentError, "Color must be one of #{ COLORS.keys }, got `#{ color }' instead!" unless COLORS.key? color | |
@name = name.to_s | |
@color = color | |
end | |
def to_s | |
[name, COLORS[ color ]].join("\n") | |
end | |
def to_binary binary | |
CFPropertyList::CFString.new(to_s).to_binary(binary) | |
end | |
end | |
class TaggedFile | |
attr_reader :pathname | |
def initialize pathname | |
@pathname = pathname | |
end | |
def tags_plist | |
CFPropertyList::List.new(data: xattrs["com.apple.metadata:_kMDItemUserTags"]) | |
end | |
def xattrs | |
Xattr.new(pathname.to_s) | |
end | |
def get_tags | |
tags_plist | |
.value | |
.value | |
.map do |attr| | |
tag_tuples = attr.value.split "\n" | |
Tag.new(name: tag_tuples[0], color: tag_tuples[1].to_i) | |
end | |
end | |
def set_tag name:, color: | |
tags = get_tags | |
tags << Tag.new(name: name, color: color) | |
set_tags tags: tags | |
end | |
def remove_tag name: | |
tags = get_tags | |
tags.delete_if { |tag| tag.name == name } | |
set_tags tags: tags | |
end | |
def set_tags tags: | |
xattrs["com.apple.metadata:_kMDItemUserTags"] = tags_plist.tap do |plist| | |
plist.value = CFPropertyList::CFArray.new(tags) | |
end.to_str | |
end | |
end | |
class Runner | |
def run | |
file = TaggedFile.new Pathname.new("tagtest/1") | |
tags = [ | |
Tag.new(name: "Test", color: :red), | |
Tag.new(name: "Other Test", color: :gray) | |
] | |
file.set_tags tags: tags | |
end | |
end | |
Runner.new.run |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment