Hey Folks,
Does anyone know how to set kMDItemWhereFroms and other metadata from AppleScriptObjC?
-Chris
Hey Folks,
Does anyone know how to set kMDItemWhereFroms and other metadata from AppleScriptObjC?
-Chris
You can’t directly set Spotlight metadata — but you can change the information the Spotlight importer imports. This code will give you the existing quarantine information:
set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
set {theResult, qDict} to aURL's getResourceValue:(reference) forKey:(current application's NSURLQuarantinePropertiesKey) |error|:(reference) -- get quarantine dictionary
In theory you can probably change the values and replace the old version. But you may end up causing problems if you just change one value — I can see a UUID in there, as well as a date and some other values. Can I ask why you would want to do that?
Hey Shane,
I’m setting the Where From metadata of a file.
Presently I only know how to do this with xattr
in the shell:
-Chris
# -----------------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2019/06/15 19:01
# dMod: 2019/06/15 19:01
# Task: Download BBEdit Notes File and Set WhereFroms MetaData
# Tags: @ccstone, @Shell, @Script, @Download, @BBEdit, @Notes, @Set, @WhereFroms, @Metadata
# -----------------------------------------------------------------------------------------
cd /Users/chris/Downloads
fileURL='https://s3.amazonaws.com/BBSW-download/12.6.5_Notes.txt'
fileName=$(basename "$fileURL")
# Download the current BBEdit beta notes file.
curl -Ls --remote-name --user-agent 'Opera/9.70 (Linux ppc64 ; U; en) Presto/2.2.1' "$fileURL"
# Set the Where From Metadata for the downloaded File.
xattr -w 'com.apple.metadata:kMDItemWhereFroms' '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><array><string>'"$fileURL"'</string></array></plist>' "$fileName"
# Create new name for file.
bbeditVersionStr=$(egrep '^version' "$fileName" | head -n 1 | awk '{ print substr($0, index($0,$2)) }' | sed -E -e 's!\)[[:blank:]]+\(!) ⇢ Beta Notes ⇢ !' -e 's!\)$!!' -e 's!^!BBEdit !' -e 's!$!.txt!')
# Rename the file.
mv "$fileName" "$bbeditVersionStr"
You probably want something like this:
use framework "Foundation"
use scripting additions
set fileURL to "https://s3.amazonaws.com/BBSW-download/12.6.5_Notes.txt"
set theURL to current application's NSURL's URLWithString:fileURL
set theName to theURL's lastPathComponent()
set theData to current application's NSData's dataWithContentsOfURL:theURL
set theDate to current application's NSDate's |date|()
set newPath to "/Users/shane/Desktop/Notes.txt" -- change to suit
set newURL to current application's NSURL's fileURLWithPath:newPath
theData's writeToURL:newURL atomically:true
set qDict to current application's NSDictionary's dictionaryWithObjects:{theURL, theDate, current application's kLSQuarantineTypeWebDownload} forKeys:{current application's kLSQuarantineOriginURLKey, current application's kLSQuarantineTimeStampKey, current application's kLSQuarantineTypeKey}
newURL's setResourceValue:qDict forKey:(current application's NSURLQuarantinePropertiesKey) |error|:(missing value)
It will probably add a quarantine agent automatically.
Hey Shane,
Thanks.
That does a nice job downloading the file.
It does.
The script still does not demonstrate how to set the Where From metadata of the downloaded file.
And I’d also like to know how to remove the Quarantine status of the file with AppleScriptObjC if possible.
(I know how to do it with xattr
.)
I’m not sure why the Spotlight importer is not updating the Spotlight database from the new info. I don’t see any other place to change it.
Set the resource value for it to missing value
. Just don’t do it to a file that has already had it removed.
Hmm,
Maybe I’m missing something here, but why not using the shell once you have downloaded (and renamed)
set zScript to "xattr -w 'com.apple.metadata:kMDItemWhereFroms' " & "'<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version=\"1.0\"><array><string>" & quoted form of theURL & "</string></array></plist>' " & quoted form of theFilePath
do shell script zScript
Hey Andreas,
Pease see my post #13, where I did just that.
The reason is: I want to know if it can be done with with AppleScriptObjC.
When I’m working with AppleScript I prefer not to use do shell script commands, unless they are the best (or only) method available.
-Chris
Hey Folks,
Coming back to this…
I normally review BBEdit beta release notes in a web browser (Brave), so I decided to scrape the text from the browser instead of freshly download the remote file.
In time the script below will be much more comprehensive, but for now it is only handling the job specified above.
Starting with this web page:
https://s3.amazonaws.com/BBSW-download/12.6.6_Notes.txt
The script below will:
-Chris
------------------------------------------------------------
# dNam: New Downloader Script for FRONT BROWSER (instead of browser-specific).
# - Set for BRAVE for development.
# dCre: 2019/06/21 17:27
# dMod: 2019/06/07 13:04
------------------------------------------------------------
(*
NOTES:
• All Chrome-based browsers use the same syntax!
*)
------------------------------------------------------------
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
------------------------------------------------------------
--» Discover what browser is Frontmost.
set jsCmdStr to "document.URL"
# set browserURL to doJavaScriptInFrontBrowser(jsCmdStr)
set browserURL to doJavaScriptInBrave(jsCmdStr)
------------------------------------------------------------
--» SPECIAL-CASE DOWNLOADS
------------------------------------------------------------
--» BBEdit Beta Notes
------------------------------------------------------------
if (its reMatch:"https://s3.amazonaws.com/BBSW-download/\\d+\\.\\d+\\.\\d+_Notes.txt" inText:browserURL) ≠ "" then
set jsCmdStr to "
document.body.parentNode.textContent
"
set browserText to doJavaScriptInBrave(jsCmdStr)
set thePattern to "(?m)^(version)\\h+(\\d+[\\d.]+)\\h+(\\(\\d+\\))\\h+\\((\\d+[\\d-]+)\\)"
set templateStr to "BBEdit $2 $3 Beta Notes ⇢ $4.txt"
set findResult to its regexFindWithCapture:thePattern fromString:browserText resultTemplate:templateStr
if length of findResult ≠ 0 then
set findResult to item 1 of findResult
set newFilePath to (POSIX path of (path to downloads folder as text)) & findResult
its writeString:browserText toPath:newFilePath
set newBBEditVersionFile to alias POSIX file newFilePath
--» Set kMDItemWhereFroms of the newly created file.
set shCmdStr to "xattr -w 'com.apple.metadata:kMDItemWhereFroms' '<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version=\"1.0\"><array><string>'" & quoted form of browserURL & "'</string></array></plist>' " & quoted form of newFilePath
do shell script shCmdStr
tell application "Finder"
activate
reveal newBBEditVersionFile
end tell
# "" --» •••••
end if
end if
------------------------------------------------------------
--» HANDLERS
------------------------------------------------------------
on doJavaScriptInBrave(jsCmdStr)
try
tell application "Brave Browser" to tell front window's active tab to execute javascript jsCmdStr
on error e
error "Error in handler doJavaScriptInBrave() of library NLb!" & return & return & e
end try
end doJavaScriptInBrave
------------------------------------------------------------
on doJavaScriptInFrontBrowser(jsCmdStr)
set frontBrowserName to getFrontBrowserName() of me
if frontBrowserName = "Brave Browser" then
tell application "Brave Browser" to tell front window's active tab to execute javascript jsCmdStr
else if frontBrowserName = "Google Chrome" then
tell application "Google Chrome" to tell front window's active tab to execute javascript jsCmdStr
else if frontBrowserName = "Safari" then
tell application "Safari" to do JavaScript jsCMD in front document
end if
end doJavaScriptInFrontBrowser
------------------------------------------------------------
on getFrontBrowserName()
set frontBrowser to path to frontmost application as text
tell application frontBrowser to set frontBrowserName to its name
return frontBrowserName
end getFrontBrowserName
------------------------------------------------------------
on cngStr:findString intoString:replaceString inString:dataString
set anNSString to current application's NSString's stringWithString:dataString
set dataString to (anNSString's stringByReplacingOccurrencesOfString:findString withString:replaceString ¬
options:(current application's NSRegularExpressionSearch) range:{0, length of dataString}) as text
end cngStr:intoString:inString:
------------------------------------------------------------
on reMatch:findPattern inText:theText
set theNSString to current application's NSString's stringWithString:theText
set theOptions to ((current application's NSRegularExpressionDotMatchesLineSeparators) as integer) + ((current application's NSRegularExpressionAnchorsMatchLines) as integer)
set theRegEx to current application's NSRegularExpression's regularExpressionWithPattern:findPattern options:theOptions |error|:(missing value)
set theFinds to theRegEx's matchesInString:theNSString options:0 range:{location:0, |length|:theNSString's |length|()}
set theFinds to theFinds as list -- so we can loop through
set theResult to {} -- we will add to this
repeat with i from 1 to count of items of theFinds
set theRange to (item i of theFinds)'s range()
set end of theResult to (theNSString's substringWithRange:theRange) as string
end repeat
return theResult
end reMatch:inText:
------------------------------------------------------------
on regexFindWithCapture:thePattern fromString:theString resultTemplate:templateStr
set theString to current application's NSString's stringWithString:theString
set theRegEx to current application's NSRegularExpression's regularExpressionWithPattern:thePattern options:0 |error|:(missing value)
set theFinds to theRegEx's matchesInString:theString options:0 range:{0, theString's |length|()}
set theResult to current application's NSMutableArray's array()
repeat with aFind in theFinds
set foundString to (theRegEx's replacementStringForResult:aFind inString:theString |offset|:0 template:templateStr)
(theResult's addObject:foundString)
end repeat
return theResult as list
end regexFindWithCapture:fromString:resultTemplate:
------------------------------------------------------------
on writeString:aString toPath:posixPath
set anNSString to current application's NSString's stringWithString:aString
anNSString's writeToFile:posixPath atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeString:toPath:
------------------------------------------------------------