Ruby, irb and spotlight - possibly some AppleScript
I've been playing with ruby, specifically interactive ruby and now playing with the command line spotlight commands mdfind and mdls.
Basically I'm trying to write a small collection of functions that can find image files which are certain types, that are specific dimensions, or larger than a certain dimensions, or have been created in the last x days, or created y months ago.
I'm using the ruby that comes with Mavericks and I'm running 10.9.3, I'm not running the ruby code in any kind of server environment. Just a user account. I would like to see what I've written used by others so since I'm new to this I thought I'd get someone else to pass an eye over it.
I'd also like to do the same for AppleScript, but though I've written quite a bit of AppleScript in the distant past I'm pretty rusty now and know longer know how to go write a library of routines, so hints on how to do that would appreciated.
I think I've covered myself on security related issues, no shell expansion and I believe the options passed in are just arguments for the command which is the first item. But I would still like comments from someone with experience?
For testing purposes I've got a require_relative in a .irbrc file where I start irb from which loads the following:
#!/usr/bin/env ruby
require 'Open3'
module SpotlightCommand
def self.get_imagewidthheight(imageFilePath)
finalResult = [ -1, -1 ] # width, height
resultStr, exitVal = Open3.capture2("mdls", "-name", "kMDItemPixelWidth",
"-name", "kMDItemPixelHeight", imageFilePath)
unless exitVal.exitstatus.zero?
return finalResult
end
resultArray = resultStr.split("\n")
if (resultArray.length.eql? 2)
tempArray = resultArray[0].split(" ")
if (tempArray[0].eql? "kMDItemPixelHeight")
finalResult[1] = tempArray[2].to_i
elsif (tempArray[0].eql? "kMDItemPixelWidth")
finalResult[0] = tempArray[2].to_i
end
tempArray = resultArray[1].split
if (tempArray[0].eql? "kMDItemPixelWidth")
finalResult[0] = tempArray[2].to_i
elsif (tempArray[0].eql? "kMDItemPixelHeight")
finalResult[1] = tempArray[2].to_i
end
end
return finalResult
end
def self.make_contenttypepartofquery(fileType)
contentTypeQueryPart = nil
typesHash = { :"public.jpeg" => "public.jpeg",
:"public.png" => "public.png",
:"public.tiff" => "public.tiff",
:"com.compuserve.gif" => "com.compuserve.gif" }
unless fileType.nil?
fileType = typesHash[fileType.intern]
end
if fileType.nil?
contentTypeQueryPart = "kMDItemContentTypeTree == public.image"
else
contentTypeQueryPart = "kMDItemContentType == " + fileType
end
return contentTypeQueryPart
end
def self.find_imagefileswith_widthheightfiletype(width, height,
fileType = nil, onlyInDirPath = nil)
theCommand = [ "mdfind" ]
unless onlyInDirPath.nil?
theCommand.push("-onlyin")
theCommand.push(onlyInDirPath)
end
query = self.make_contenttypepartofquery(fileType) + " && "
query += "kMDItemPixelWidth == " + width.to_s + " && "
query += "kMDItemPixelHeight == " + height.to_s
theCommand.push(query)
puts theCommand.to_s
theOutput = ""
IO.popen(theCommand) do |io|
theOutput = io.read
end
theOutput = theOutput.split("\n")
return theOutput
end
def self.find_imagefileswith_widthheightgreaterthan_filetype(
greaterThanWidth, greaterThanHeight, fileType = nil, onlyInDirPath = nil)
theCommand = [ "mdfind" ]
unless onlyInDirPath.nil?
theCommand.push("-onlyin")
theCommand.push(onlyInDirPath)
end
query = self.make_contenttypepartofquery(fileType) + " && "
query += "kMDItemPixelWidth >= " + greaterThanWidth.to_s + " && "
query += "kMDItemPixelHeight >= " + greaterThanHeight.to_s
theCommand.push(query)
puts theCommand.to_s
theOutput = ""
IO.popen(theCommand) do |io|
theOutput = io.read
end
theOutput = theOutput.split("\n")
return theOutput
# return ""
end
def self.find_imagefilescreated_inmonthsago(
monthsAgo, fileType = nil, onlyInDirPath = nil)
monthsAgo =(-( monthsAgo.to_i )).to_s
monthsAgoPlus1 = (monthsAgo.to_i + 1).to_s
theCommand = [ "mdfind" ]
unless onlyInDirPath.nil?
theCommand.push("-onlyin")
theCommand.push(onlyInDirPath)
end
query = self.make_contenttypepartofquery(fileType) + " && "
query += "kMDItemContentCreationDate > $time.this_month(" + monthsAgo+")" +
" && kMDItemContentCreationDate < $time.this_month("+monthsAgoPlus1+")"
theCommand.push(query)
puts theCommand.to_s
theOutput = ""
IO.popen(theCommand) do |io|
theOutput = io.read
end
theOutput = theOutput.split("\n")
return theOutput
end
def self.find_imagefilescreated_sincedaysago(
daysAgo, fileType = nil, onlyIn = nil)
daysAgo = (-(daysAgo.to_i)).to_s
theCommand = [ "mdfind" ]
unless onlyIn.nil?
theCommand.push("-onlyin")
theCommand.push(onlyIn)
end
query = self.make_contenttypepartofquery(fileType) + " && "
query += "kMDItemContentCreationDate >= $time.today(" + daysAgo + ")"
theCommand.push(query)
puts theCommand.to_s
theOutput = ""
IO.popen(theCommand) do |io|
theOutput = io.read
end
theOutput = theOutput.split("\n")
return theOutput
end
end
When running interactive ruby (irb) I then call the routines like so:
results = SpotlightCommand.get_imagewidthheight("/Users/ktam/Pictures/NewYearsEveAndJan20 04/DSCN0706.JPG") #1
results = SpotlightCommand.find_imagefileswith_widthheightfiletype(2272, 1704, "public.image", "/Users/ktam/Pictures") # 2
results = SpotlightCommand.find_imagefileswith_widthheightgreaterthan_filetype(2273, 1705) # 3
results = SpotlightCommand.find_imagefilescreated_inmonthsago(3, "public.image") # 4
results = SpotlightCommand.find_imagefilescreated_sincedaysago(30, "public.image") # 5