Mojave – Apply Tags to a file?

Thanks Shane.
What you wrote may explain why several keys may be used to describe the same string.
As I am curious, I ran my sample script upon Finder 10.12.6 and - I am lucky - the “easy to remember keys” available in Finder 10.13.6 were already available in the old version.

In practice it’s not really important. I never had to use such keys. I use localized string when I have to write GUI scripting code where the name of UI elements are always localized.
The fact that some tables are unavailable in English.lprog is more annoying.
I’m wondering were are the English strings defined in such cases.

I’m really puzzled by the key “tCs-xJ-UEw.title” in the table ArrangeByMenu.strings.
Most of the time the local string means volume but sometimes it’s really different.
For instance, the danish key is Enhed which is supposed to mean Unit.

And of course I’m always unable to find where is this string really used.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 17 mai 2019 12:08:03

How would the modified script of Shane Stanley look like (kerflooey) if you dont want to choose a label, but have it set to a specific label?

Hi. The script I use is below, which I use in Catalina. If you choose labels, they are applied. If you don’t choose a label, all current labels are removed. Not sure about your question, though. You want to not choose a label, but apply a specific label?


use AppleScript version "2.3.1"
use scripting additions
use framework "Foundation"

tell application "Finder"
	set theItems to the selection
end tell

set tagList to choose from list {"Red", "Orange", "Yellow", "Green", "Blue", "Gray", "Purple"} with title "Tag Selected Items" with prompt "Choose colors:" OK button name "Apply" cancel button name "Cancel" with multiple selections allowed and empty selection allowed

repeat with thisItem in theItems
	set theFile to POSIX path of (thisItem as alias)
	
	(its setTags:tagList forPath:theFile)
end repeat

on returnTagsFor:posixPath -- get the tags
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
	if theTags = missing value then return {} -- because when there are none, it returns missing value
	return theTags as list
end returnTagsFor:

on setTags:tagList forPath:posixPath -- set the tags, replacing any existing
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end setTags:forPath:

on addTags:tagList forPath:posixPath -- add to existing tags
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	-- get existing tags
	set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
	if theTags ≠ missing value then -- add new tags
		set tagList to (theTags as list) & tagList
		set tagList to (current application's NSOrderedSet's orderedSetWithArray:tagList)'s allObjects() -- delete any duplicates
	end if
	aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end addTags:forPath:



Hi, yes Kerflooey. I tried the script and it works fine. :slight_smile:

I would like to have it set to a fixed chosen label. That way I can make an automator “quick action”.

The goal is to right click a folder in finder that is red, go into services and pick the script that changes it to green.

When I try to do it only using automator I get green label in addition to the red.
So this AppleScript would be the solution I need.

If I understand correctly, you want to select a file (or files) and apply a fixed-text tag to it. A quick and dirty approach is to remove or comment out the “set tagList to…” line near the beginning and replace it with a line to just set the tag to whatever you want. For example:


--set tagList to choose from list {"Red", "Orange", "Yellow", "Green", "Blue", "Gray", "Purple"} with title "Tag Selected Items" with prompt "Choose colors:" OK button name "Apply" cancel button name "Cancel" with multiple selections allowed and empty selection allowed

set tagList to {"Red"} 

-- or, to remove a tag: 
--set tagList to {""}




kerflooey, you are the MAN! :cool:

Very grateful for that help! It worked flawlessly.

Thanks dude!

kerflooey, you are the MAN! cool

Ha, no. That would be Shane! :slight_smile: Glad it worked for you.

Yes, thanks to Shane too! :cool:

Using Shane’s code above, I am able to REMOVE a custom tag (one that is created by the user, such as “Photo”, and not just the system label names like “Green”), but I can not CREATE a custom label on a file, I am only able to add a color name from the old Finder labels to a file. Does anyone know if there is a work around to this?

Currently on Monterey.

Thanks!

Hey Chris,

It’s generally a good idea to provide an example of the code that’s failing.

This works for me – but I’m still on Mojave.

-Chris

--------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2023/01/06 18:23
# dMod: 2023/01/06 18:23 
# Appl: Finder
# Task: Add a Custom Tag to the Item Selected in the Finder.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @ASObjC, @Finder, @Add, @Custom, @Tag
--------------------------------------------------------
use AppleScript version "2.4" --» Yosemite or later
use framework "Foundation"
use scripting additions
--------------------------------------------------------

tell application "Finder" to set finderSelectionList to selection as alias list
if length of finderSelectionList = 0 then error "No files were selected in the Finder!"
set posixPath to POSIX path of item 1 of finderSelectionList

set tagList to {"NutterButterBar"}
its addTags:tagList forPath:posixPath

--------------------------------------------------------
--» HANDLERS
--------------------------------------------------------
on addTags:tagList forPath:posixPath -- add to existing tags
   set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
   -- get existing tags
   set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
   if theTags ≠ missing value then -- add new tags
      set tagList to (theTags as list) & tagList
      set tagList to (current application's NSOrderedSet's orderedSetWithArray:tagList)'s allObjects() -- delete any duplicates
   end if
   aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end addTags:forPath:
--------------------------------------------------------

Thanks Chris.
Noted about the code example.

Your example is 1 of 3 handlers in Shane’s code from above. I am finding that it is the following handler that is not working for some reason, but it is not completely obvious to me why this one is broken.

on setTags:tagList forPath:posixPath -- set the tags, replacing any existing
set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end setTags:forPath:

Thanks!

You’re still not showing your script that’s failing – therefore we cannot examine it for problems…

This works for me on Mojave.

--------------------------------------------------------
use AppleScript version "2.4" --» Yosemite or later
use framework "Foundation"
use scripting additions
--------------------------------------------------------

tell application "Finder" to set finderSelectionList to selection as alias list
if length of finderSelectionList = 0 then error "No files were selected in the Finder!"
set posixPath to POSIX path of item 1 of finderSelectionList

set tagList to {"Nonsense"}

its setTags:tagList forPath:posixPath

--------------------------------------------------------
--» HANDLERS
--------------------------------------------------------
on setTags:tagList forPath:posixPath -- set the tags, replacing any existing
   set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
   aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end setTags:forPath:
--------------------------------------------------------

Your code works on Monterey for me as well.

Here is my FULL code that is not working.

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
set theTag to "Art"

tell application "Finder"
   set theFiles to selection
end tell
repeat with f from 1 to (count theFiles)
   set theItem to item f of theFiles as alias
   set theFile to POSIX path of theItem
   set theTags to (its returnTagsFor:theFile)
   if theTags does not contain theTag then
      set newTags to theTag
      repeat with i from 1 to (count theTags)
         set oldTag to item i of theTags
         set end of newTags to oldTag
      end repeat
      (its setTags:newTags forPath:theFile)
   else
      set newTags to {}
      repeat with i from 1 to (count theTags)
         set oldTag to item i of theTags
         if oldTag does not contain "Art" then
            set end of newTags to oldTag
         end if
      end repeat
      (its setTags:newTags forPath:theFile)
   end if
end repeat

on returnTagsFor:theFile -- get the tags
   set aURL to current application's |NSURL|'s fileURLWithPath:theFile -- make URL
   set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
   if theTags = missing value then return {} -- because when there are none, it returns missing value
   return theTags as list
end returnTagsFor:

on setTags:newTags forPath:theFile -- set the tags, replacing any existing
   set aURL to current application's |NSURL|'s fileURLWithPath:theFile -- make URL
   aURL's setResourceValue:newTags forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end setTags:forPath:

Okay… It looks to me like you’re trying to toggle whether the given tag exists in the selected item(s) in the Finder.

It’s a good idea to provide some explanatory text to posted scripts, so people don’t have to spend time figuring out what you’re doing. You’ll get more accurate and quicker help that way.

  1. You’re trying to use Finder-References outside the Finder.
  2. In your first IF it looks like you’re trying to concatenate a string instead of add to a list.

Here’s how I’d go about your task:

--------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2023/01/09 06:04
# dMod: 2023/01/09 06:04 
# Appl: Finder
# Task: 
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @ASObjC, @Finder
--------------------------------------------------------
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
--------------------------------------------------------

set tagToProcess to "Art"

# Without ‘as alias list’ you get Finder-References which don't work outside the Finder.
tell application "Finder"
   set finderSelectionList to selection as alias list
end tell

repeat with theItem in finderSelectionList -- No need for a counter.
   
   set itemPath to POSIX path of theItem
   set tagList to (its returnTagsFor:itemPath)
   
   if tagList contains tagToProcess then
      
      set tagList to (its removeListItem:tagToProcess fromList:tagList)
      (its setTags:tagList forPath:itemPath) -- Change the list of tags
      
   else if tagList does not contain tagToProcess then
      
      (its addTags:{tagToProcess} forPath:itemPath)
      
   end if
   
end repeat

--------------------------------------------------------
--» HANDLERS
--------------------------------------------------------
on addTags:tagList forPath:posixPath -- add to existing tags
   set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
   -- get existing tags
   set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
   if theTags ≠ missing value then -- add new tags
      set tagList to (theTags as list) & tagList
      set tagList to (current application's NSOrderedSet's orderedSetWithArray:tagList)'s allObjects() -- delete any duplicates
   end if
   aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end addTags:forPath:
--------------------------------------------------------
on removeListItem:listItemName fromList:theList
   set theList to current application's NSMutableArray's arrayWithArray:theList
   theList's removeObject:listItemName
   return theList as list
end removeListItem:fromList:
--------------------------------------------------------
on returnTagsFor:itemPath -- Get the tags
   set aURL to current application's |NSURL|'s fileURLWithPath:itemPath -- make URL
   set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
   if theTags = missing value then return {} -- because when there are none, it returns missing value
   return theTags as list
end returnTagsFor:
--------------------------------------------------------
on setTags:newTags forPath:itemPath -- Set the tags, replacing any existing
   set aURL to current application's |NSURL|'s fileURLWithPath:itemPath -- make URL
   aURL's setResourceValue:newTags forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end setTags:forPath:
--------------------------------------------------------

Note that if you’re serious about learning AppleScript and not using Script Debugger you’re missing a bet.

Being able to step through scripts and visualize what they’re doing is a game changer.

That works. Thank you very much Chris. It was more complicated (with the ASOBJC Handlers) than I had hopped with just edited some of Shane’s original script!

In Terminal.app, I used Homebrew to install the command line tool tag … using the command brew install tag

I use it with AppleScript all the time. One of its awesome features is the ability to tag files with custom tags on the fly.

For example, let’s say that I want to add a custom tag named “New Tag”, to the currently selected files in Finder… This following AppleScript code would do the job.

property customTag : "New Tag"

tell application "Finder" to set selectedFiles to selection as alias list

repeat with thisFile in selectedFiles
	do shell script "/usr/local/bin/tag -a " & quoted form of customTag & ¬
		space & quoted form of POSIX path of thisFile
end repeat

With Shane’s FileManagerLib library, it cant be shorter:

use AppleScript version "2.4"
use script "FileManagerLib"
use scripting additions

tell application "Finder" to set theFiles to selection as alias list

repeat with aFile in theFiles
	set tags of {"Art"} to aFile
end repeat
1 Like

That’s some weird syntax, but it does work like a charm.

I started out with more vanilla AppleScript, but it was just more efficient to use ASObjC.

Might as well embrace ASObjC – it’s here to stay – at least as long as we continue to have AppleScript.

I would just turn it around:

set tags of theFile to {"Art"}

That makes more obvious sense to me.