AsObjC: get Extended Info for File System items (AsObjC)

The following script returns the 36 most requested (in my opinion) information from the filesystem item’s metadata. If I forgot some important metadata, feel free to correct me.


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set filePath to POSIX path of (choose file)
my getExtendedInfo:filePath

on getExtendedInfo:filePath
	local mdItem, mdItemAttributes
	script o
		on readMetadata(attr, coecion)
			if mdItemAttributes's containsObject:attr then
				if (mdItem's valueForAttribute:attr) is missing value then return missing value
				if coecion is date then return (mdItem's valueForAttribute:attr) as date
				if coecion is list then return (mdItem's valueForAttribute:attr) as list
				if coecion is text then return (mdItem's valueForAttribute:attr) as text
				if coecion is integer then return (mdItem's valueForAttribute:attr) as integer
				if coecion is boolean then return (mdItem's valueForAttribute:attr) as boolean
			end if
			return missing value
		end readMetadata
	end script
	set targetURL to current application's |NSURL|'s fileURLWithPath:filePath
	set mdItem to current application's NSMetadataItem's alloc()'s initWithURL:targetURL
	set mdItemAttributes to mdItem's attributes()
	set ContentTypeTree to o's readMetadata("kMDItemContentTypeTree", list)
	set ContentType to o's readMetadata("kMDItemContentType", text)
	set PhisicalSize to o's readMetadata("kMDItemPhysicalSize", integer)
	set UsedDates to o's readMetadata("kMDItemUsedDates", list)
	set LastUsedDates to o's readMetadata("kMDItemLastUsedDates", list)
	set LastUsedDate_Ranking to o's readMetadata("kMDItemLastUsedDate_Ranking", date)
	set UseCount to o's readMetadata("kMDItemUseCount", integer)
	set InterestingDate_Ranking to o's readMetadata("kMDItemInterestingDate_Ranking", date)
	set DisplayName to o's readMetadata("kMDItemDisplayName", text)
	set DisplayNameWithExtensions to o's readMetadata("_kMDItemDisplayNameWithExtensions", text)
	set |Kind| to o's readMetadata("kMDItemKind", text)
	set DateAdded_Ranking to o's readMetadata("kMDItemDateAdded_Ranking", date)
	set ContentModificationDate_Ranking to o's readMetadata("kMDItemContentModificationDate_Ranking", date)
	set DateAdded to o's readMetadata("kMDItemDateAdded", date)
	set DocumentIdentifier to o's readMetadata("kMDItemDocumentIdentifier", integer)
	set ContentModificationDate to o's readMetadata("kMDItemContentModificationDate", date)
	set ContentCreationDate_Ranking to o's readMetadata("kMDItemContentCreationDate_Ranking", date)
	set ContentCreationDate to o's readMetadata("kMDItemContentCreationDate", date)
	set |Version| to o's readMetadata("kMDItemVersion", text)
	set LogicalSize to o's readMetadata("kMDItemLogicalSize", integer)
	set WhereFroms to o's readMetadata("kMDItemWhereFroms", list)
	set DownloadedDate to o's readMetadata("kMDItemDownloadedDate", date)
	set FSName to o's readMetadata("kMDItemFSName", text)
	set FSSize to o's readMetadata("kMDItemFSSize", integer)
	set FSCreationDate to o's readMetadata("kMDItemFSCreationDate", date)
	set FSContentChangeDate to o's readMetadata("kMDItemFSContentChangeDate", date)
	set FSOwnerUserID to o's readMetadata("kMDItemFSOwnerUserID", text)
	set FSOwnerGroupID to o's readMetadata("kMDItemFSOwnerGroupID", text)
	set FSNodeCount to o's readMetadata("kMDItemFSNodeCount", text)
	set FSInvisible to o's readMetadata("kMDItemFSInvisible", boolean)
	set FSTypeCode to o's readMetadata("kMDItemFSTypeCode", integer)
	set FSCreatorCode to o's readMetadata("kMDItemFSCreatorCode", integer)
	set FSFinderFlags to o's readMetadata("kMDItemFSFinderFlags", list)
	set FSHasCustomIcon to o's readMetadata("kMDItemFSHasCustomIcon", boolean)
	set FSIsExtensionHidden to o's readMetadata("kMDItemFSIsExtensionHidden", boolean)
	set FSIsStationery to o's readMetadata("kMDItemFSIsStationery", boolean)
	set FSLabel to o's readMetadata("kMDItemFSLabel", integer)
	return {ContentTypeTree:ContentTypeTree, ContentType:ContentType, FSTypeCode:FSTypeCode} & ¬
		{PhisicalSize:PhisicalSize, LogicalSize:LogicalSize, FSSize:FSSize, FSName:FSName} & ¬
		{UseCount:UseCount, InterestingDate_Ranking:InterestingDate_Ranking} & ¬
		{DisplayName:DisplayName, DisplayNameWithExtensions:DisplayNameWithExtensions} & ¬
		{|Kind|:|Kind|, |Version|:|Version|, DocumentIdentifier:DocumentIdentifier} & ¬
		{DateAdded:DateAdded, DateAdded_Ranking:DateAdded_Ranking} & ¬
		{WhereFroms:WhereFroms, DownloadedDate:DownloadedDate} & ¬
		{ContentCreationDate:ContentCreationDate, ContentCreationDate_Ranking:ContentCreationDate_Ranking} & ¬
		{ContentModificationDate:ContentModificationDate, FSContentChangeDate:FSContentChangeDate} & ¬
		{UsedDates:UsedDates, LastUsedDates:LastUsedDates} & ¬
		{LastUsedDate_Ranking:LastUsedDate_Ranking, InterestingDate_Ranking:InterestingDate_Ranking} & ¬
		{FSCreationDate:FSCreationDate, FSCreatorCode:FSCreatorCode} & ¬
		{FSOwnerUserID:FSOwnerUserID, FSOwnerGroupID:FSOwnerGroupID} & ¬
		{FSNodeCount:FSNodeCount, FSInvisible:FSInvisible, FSLabel:FSLabel} & ¬
		{FSFinderFlags:FSFinderFlags, FSHasCustomIcon:FSHasCustomIcon} & ¬
		{FSIsExtensionHidden:FSIsExtensionHidden, FSIsStationery:FSIsStationery}
end getExtendedInfo:

KniazidisR. Thanks for the great post. This is a general area I’ve been working to understand, and your script is very informative.

Most people who want to obtain a single file metadata value appear to use the shell, and my search did not yield a simple ASObjC code snippet to accomplish that task. I assume the following is the approach to use with ASObjC:

use framework "Foundation"
use scripting additions

set theFile to POSIX path of (choose file)
set theFile to current application's |NSURL|'s fileURLWithPath:theFile
set mdItem to current application's NSMetadataItem's alloc()'s initWithURL:theFile

-- get a single value
set modificationDate to mdItem's valueForAttribute:"kMDItemContentModificationDate" -- an NSDate

-- get multiple values and retrieve one of those values
set theDates to mdItem's valuesForAttributes:{"kMDItemContentCreationDate", "kMDItemContentModificationDate"} -- a dictionary of NSDates
set modificationDate to theDates's valueForKey:"kMDItemContentModificationDate"

-- set allAttributes to mdItem's attributes() -- an array of all attributes FWIW

FWIW, there appears to be two ASObjC methods by which one can get detailed information about a file. The first is NSMetadataItem as you explain, and the other is NSURL’s getResourceValue method. The following thread contains Fredrik71’s script which gives a good overview of available data using getResourceValue:

https://macscripter.net/viewtopic.php?pid=206259

Perhaps there’s a reason you’ve enumerated the attributes manually, but on the off chance you weren’t aware these attribute keys can be read en masse—or for anyone else who might not want to go through such a ballache—the following handler will return a record very similar to the one yours constructs overtly:

use framework "Foundation"
use scripting additions

on metadataForFileURL:fileURL
 		tell my NSMetadataItem's alloc() to tell initWithURL_(fileURL) ¬
 				to return the valuesForAttributes_(its attributes()) ¬
 				as record
end metadataForFileURL:

metadataForFileURL_(choose file)

The script written by me is intended for users who are interested in a certain prefered set of file metadata.

That’s its point, not getting the existing file metadata. I don’t know how to explain to you that this is just my preference if you don’t want to accept it.

OK, I don’t know what your problem is this time, but as you didn’t explain the intention of your script, and given that I don’t read minds, I wasn’t to know, was I ? I, however, did explain in my post that I was offering the code snippet for you (should you have needed it, which I’m guessing you didn’t) and for anyone else that might find it helpful.

Last time I was met with your hostility, I seem to recall you insisting I contribute code instead of writing “useless” comments. It seems I’m damned if I do, and damned if I don’t with you.

I would appreciate it the next time you wish to reply to my post, you ensure that your remarks pertain wholly to the topic of discussion and/or any code snippets that are shared. Please do not continue to direct comments personally at me or about me. Thank you.