Move a group of files to a new folder in parent directory

Hi,

I’m trying to automate a time consuming process that I’ve been doing by hand. Essentially I need to be able to drop a folder on a script and have it find a move files that are created from a panorama stitching program called PtGui.

PTGui is great right up until you want to automate the naming and placement of your created files.

This is the result I get out of PTGui:
https://i.imgur.com/o9Qk29R.png

I would like to have a droplet that finds these files and if they’re in the wrong folder (something)_Hdri_Raw: I would like to take take the .hdr .pts and .mov file and move them into a new folder within the parent folder called (Parent Folder)_Stitched. I would also like to rename the three files (Parent Folder)_Stitched

This is the Desired result:
https://i.imgur.com/NduJ3ay.png

The files will always be found in a folder (something)_Hdri_Raw (upper/lowercase varies depending on the project)

The file extensions will be .pts .mov and (.hdr OR .exr (depending on the project))
The naming of the original files.

I’m trying to do it with System Events and something tells me that’s not the best way to do it.
Any help would be greatly appreciated.

Assuming you drag-and-drop the _HDRI folder, something like this:

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

on open {theFolder}
	set posixPath to POSIX path of theFolder
	set folderURL to current application's |NSURL|'s fileURLWithPath:posixPath
	-- create _Stitched folder if necessary
	set folderName to folderURL's lastPathComponent()
	set stitchedFolderURL to (folderURL's URLByAppendingPathComponent:(folderName's stringByAppendingString:"_Stitched"))
	(fileManager's createDirectoryAtURL:stitchedFolderURL withIntermediateDirectories:true attributes:(missing value) |error|:(missing value))
	-- make file manager
	set fileManager to current application's NSFileManager's new()
	-- get contents of _Raw folder
	set rawFolderURL to (folderURL's URLByAppendingPathComponent:(folderName's stringByAppendingString:"_Raw"))
	set theURLs to fileManager's contentsOfDirectoryAtURL:rawFolderURL includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	-- filter files you want to move
	set thePred to current application's NSPredicate's predicateWithFormat_("pathExtension IN %@", {"pts", "mov", "hdr", "exr"})
	set theURLs to (theURLs's filteredArrayUsingPredicate:thePred)
	-- move them
	repeat with aURL in theURLs
		set newName to aURL's lastPathComponent()
		(fileManager's moveItemAtURL:aURL toURL:(stitchedFolderURL's URLByAppendingPathComponent:newName) |error|:(missing value))
	end repeat
end open

Your sample suggests you might also want the file names changed, in which case the last repeat in the above would instead probably need to be something like:

repeat with aURL in theURLs
	set newName to ((folderName's stringByAppendingString:"_Raw_Stitched")'s stringByAppendingPathExtension:(aURL's pathExtension()))
	(fileManager's moveItemAtURL:aURL toURL:(stitchedFolderURL's URLByAppendingPathComponent:newName) |error|:(missing value))
end repeat

Shane,

Thanks for this! Is there a way this script could be modified to be able to drop a higher level folder than just the _hdri folder–have it repeat for each subfolder by looking for folders ending with “_Hdri_Raw” ?

That way it could quickly run through dozens or even hundreds of folders with minimal interaction?

Are you talking recursively, or just all subfolders in a particular folder?

Forgive me, I’m not familiar with the term recursively in this context.

If you look at this image: https://i.imgur.com/77Zp5sah.png

I would like to be able to drop the HDRI_Test folder.

I assume the _Ref folders are ignored.

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

on open {theFile}
	set posixPath to POSIX path of theFile
	set theNSURL to current application's |NSURL|'s fileURLWithPath:posixPath
	my checkFolderURL:theNSURL
	set theNSURL to missing value
	display dialog "Finished." buttons {"OK"} default button 1
end open

on checkFolderURL:folderURL
	-- make file manager
	set fileManager to current application's NSFileManager's new()
	-- get contents of folder
	set theURLs to fileManager's contentsOfDirectoryAtURL:folderURL includingPropertiesForKeys:{current application's NSURLIsDirectoryKey, current application's NSURLIsPackageKey} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	repeat with aURL in theURLs
		-- is it a directory?
		set {theResult, isDirectory} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
		if isDirectory as boolean then -- check it's not a package
			set {theResult, isPackage} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLIsPackageKey) |error|:(missing value))
			-- is it not a package?
			if not isPackage as boolean then
				set theRange to (aURL's |path|()'s rangeOfString:"_hdri$|_hdri_0\\d$" options:((current application's NSRegularExpressionSearch) + (get current application's NSCaseInsensitiveSearch)))
				if |length| of theRange > 0 then
					-- check for enclosed _Raw folder
					set rawFolderPath to (aURL's |path|()'s stringByAppendingPathComponent:(aURL's lastPathComponent()'s stringByAppendingString:"_Raw"))
					if (fileManager's fileExistsAtPath:rawFolderPath) as boolean then
						(my processFolderURL:aURL)
					else
						(my checkFolderURL:aURL)
					end if
				else
					(my checkFolderURL:aURL)
				end if
			end if
		end if
	end repeat
end checkFolderURL:

on processFolderURL:folderURL
	-- make file manager
	set fileManager to current application's NSFileManager's new()
	-- create _Stitched folder if necessary
	set folderName to folderURL's lastPathComponent()
	set stitchedFolderName to folderName's stringByAppendingString:"_Stitched"
	set stitchedFolderURL to (folderURL's URLByAppendingPathComponent:stitchedFolderName)
	(fileManager's createDirectoryAtURL:stitchedFolderURL withIntermediateDirectories:true attributes:(missing value) |error|:(missing value))
	-- get contents of _Raw folder
	set rawFolderURL to (folderURL's URLByAppendingPathComponent:(folderName's stringByAppendingString:"_Raw"))
	set theURLs to fileManager's contentsOfDirectoryAtURL:rawFolderURL includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	-- filter files you want to move
	set thePred to current application's NSPredicate's predicateWithFormat_("pathExtension IN %@", {"pts", "mov", "hdr", "exr"})
	set theURLs to (theURLs's filteredArrayUsingPredicate:thePred)
	-- move them
	repeat with aURL in theURLs
		set newName to (stitchedFolderName's stringByAppendingPathExtension:(aURL's pathExtension()))
		(fileManager's moveItemAtURL:aURL toURL:(stitchedFolderURL's URLByAppendingPathComponent:newName) |error|:(missing value))
	end repeat
end processFolderURL:

Fixed typos listed below
Modified for moved goalposts

I’m getting an error after exporting to application and dropping a folder:

-[__NSCFString hasSuffx:]: unrecognized selector sent to instance 0x610000262f40 (-10000)

Changing hasSuffx to hasSuffix (in case of typo) returns the following error:

*** -[BAGenericObjectNoDeleteOSAID folderName]: unrecognized selector sent to object <BAGenericObjectNoDeleteOSAID @0x6000002267a0: OSAID(1) ComponentInstance(0x810001)> (-10000)

EDIT
2nd error looks like it’s pointing at this line:
set stitchedFolderName to folderName()'s stringByAppendingString:“_Stitched”

EDIT 2
changing hasSuffx to hasSuffix and changing folderName()'s to folderName’s appears to fix the errors.

Change

set stitchedFolderName to folderName()'s stringByAppendingString:"_Stitched"

to (remove the parentheses)

set stitchedFolderName to folderName's stringByAppendingString:"_Stitched"

Two questions:

Question one:
I noticed that the folders named _Hdri_01 and _Hdri_02 don’t get fixed because it doesn’t have the suffix “hdri”

I was able to work around that by doing a bit of sloppy coding here:

	if not isPackage as boolean then
				if aURL's its (lastPathComponent()'s lowercaseString()'s hasSuffix:"_hdri") then
					(my processFolderURL:aURL)
				else if aURL's its (lastPathComponent()'s lowercaseString()'s hasSuffix:"_hdri_01") then
					(my processFolderURL:aURL)
				else if aURL's its (lastPathComponent()'s lowercaseString()'s hasSuffix:"_hdri_02") then
					(my processFolderURL:aURL)
				else if aURL's its (lastPathComponent()'s lowercaseString()'s hasSuffix:"_hdri_03") then
					(my processFolderURL:aURL)
				else
					(my checkFolderURL:aURL)
				end if
			end if

I’m wondering if there’s a more elegant solution to this?



Question 2:

Based on my testing, it looks like I have to be the exact number of directories away for the script to work because the first directory will never contain “_hdri”. And as you can see from the above, occasionally there will be a directory called “XXXX_hdri” which contains folders “XXXX_Hdri_01”, “XXXX_Hdri_02”, etc. Which also break the script. Is there any way to fix this?

Here is a sample folder I created with dummy files (all files are just jpgs with extensions renamed) that you can test on if needed.
https://www.dropbox.com/sh/wfqjikt0e9yd6dz/AADQetUyT5VJLEiqKpWQSLMca?dl=0

I know this is getting a bit more complicated than you probably wanted when you first replied, but if you help me get this up and running I will be forever grateful. Thank you so much for your effort and knowledge.

That’s right. Mind-reading is next-door.

Right. You keep moving the goalposts and the script will keep breaking.

See the latest version above.

This is brilliant!

Thank you so much. :smiley: