Creating a large set of photograph files with unique filenames

The problem should be dead simple for someone knowing Applescript; alas I am a total noob.
This is going to be a long post, so please be so kind to bear with me. It is just to provide a clear description of the problem at hand.

I shoot gymnastics sessions from time to time. More than 200 athletes take part. Photographs in each shooting can be anything from 600-1000.
Each athlete orders a number of photos that I print and then mail away to them. In each shooting, every photo shot has a unique number as a filename: 1.jpg, 2.jpg… 600.jpg.
All athletes are given also a unique id (1, 2, 3, 4) etc.
What I need to do is have a CSV file where each line contains as the first component the id of the athlete and then the photos ordered, like:

1; 50; 50; 128; 220
2; 140; 195; 210
3; 10; 10; 10

So, in the example above, Athlete with ID 1 has ordered two prints of photograph 50.jpg, and single prints of photos 128 and 220.
The script I am trying to create reads this CSV file, records the customer id and then the photos ordered and then copies the photos ordered to another common folder RENAMING the photo, according to a simple rule: (number).jpg → (cust ID)-(number)[-(seq)].jpg. As an example, again for athlete with ID 1 photos 50, 128 and 220 will be copied with the following names:
1-50.jpg
1-50-2.jpg
1-128.jpg
1-220.jpg

This way it becomes really easy to sort out the actual prints and put them in envelopes for each athlete (the filename is printed in the flip side of the photo, making identification possible).

Based on nice examples I found here I started the script below:

property photos : {}
tell application “TextEdit”
set sourceFile to (“Users:etsiot:Documents:photocopies.csv”)
set pixinfo to read file sourceFile
set entries to paragraphs of pixinfo
set {myTID, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, {“;”}}

set j to 0
repeat with i from 1 to count entries
	set lineitems to words of (item i of entries)
	set linewords to text items of lineitems
	set allwords to (every word of linewords)
	set cust to ""
	set j to j + 1
	set photos to {""}
	repeat with myItem in lineitems
		if j > 1 then
			copy myItem to the end of photos
		else
			set cust to word 1 of lineitems
		end if

	end repeat	
end repeat
set AppleScript's text item delimiters to {""}

end tell

Of course, this script is far from complete; on top I am stuck to the fact that lineitems is always a list of 1 item, and is never able to be parsed - using words for example.

I just can’t figure out what I am doing wrong with the parsing of the strings in the CSV.
Also, any pointers on how I can continue with handling the filenames are more than welcom.

Any help would be greatly appreciated.

Thanks in advance,

Vangelis

I didn’t test this… I just wrote it in my head… so there may be some bugs but give it a try. This assumes you have the CSV file.


-- these are the variables you need to set
-- make sure the folder paths end in a colon ":"
set originalPhotoFolder to (path to desktop folder as text) & "originals:" -- this is a folder with all the original photos in it
set customerPhotoFolder to (path to desktop folder as text) & "customers:" -- this is a folder which will contain the customer's ordered photos
set fileText to read file ((path to desktop folder as text) & "orders.txt") -- this is the path to the CSV file containing the customer orders

set fileTextList to paragraphs of fileText
set {myTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, (";" & space)}
try
	repeat with anOrder in fileTextList
		set thisOrderList to text items of anOrder -- now we have one line of the order in a list
		set customerID to item 1 of thisOrderList -- this is the customer number
		set orderedPhotos to items 2 thru -1 of thisOrderList -- this is a list of ordered photo numbers
		
		repeat with aPhoto in orderedPhotos
			-- calculate the original photo path
			set originalPhotoName to aPhoto & ".jpg"
			set originalPhotoPath to originalPhotoFolder & originalPhotoName
			
			-- calculate the copied photo's name
			set tempPhotoName to customerID & "-" & originalPhotoName -- get a temporary name for the copied photo
			set uniquePhotoName to uniqueName(customerPhotoFolder, tempPhotoName, "-") -- get a unique name for the file appending a number as necessary
			
			-- copy the original photo to the customers folder using the unique name
			do shell script "cp -p " & quoted form of POSIX path of originalPhotoPath & space & quoted form of POSIX path of (customerPhotoFolder & uniquePhotoName)
		end repeat
	end repeat
	
	-- clean up and alert the user
	set AppleScript's text item delimiters to myTID
	display dialog "Finished!" buttons {"OK"} default button 1 with icon note
on error theError number errorNumber
	set AppleScript's text item delimiters to myTID
	display dialog "There was an error:" & return & theError & return & return & "Error Number: " & errorNumber as text buttons {"OK"} default button 1 with icon stop
end try


(*=============== SUBROUTINES ===================*)
-- this returns a unique name for an item in a particlar folder
-- this will check a folder (fDir) and see if it contains an item named fName.
-- If it does it will add a number onto the end of the name until that name does not exist in the folder
-- the number is separated from the name by the separator
on uniqueName(fDir, fName, separator)
	set fDir to fDir as text
	if fDir does not end with ":" then set fDir to fDir & ":"
	try
		set f to (fDir & fName) as alias
		set {name:Nm, name extension:Ex, kind:Knd} to info for f
		if Ex is missing value then set Ex to ""
		if Ex is not "" then set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
		set idx to 0
		repeat
			set idx to idx + 1
			set idxNum to (text items -3 thru -1 of ("00" & idx)) as Unicode text
			
			if Knd is "Folder" then
				set checkName to (fName & separator & idxNum)
			else
				set checkName to (Nm & separator & idxNum & "." & Ex)
			end if
			try
				(fDir & checkName) as alias
			on error
				return checkName
			end try
		end repeat
	on error
		return fName
	end try
end uniqueName

Hi Hank,

Thank you very much for the effort put here!!! :slight_smile:
Really appreciated!

I will give it a try tomorrow morning and let you know.

Best Regards,

Vangelis

Hi again,

couldn’t wait to test it thru the morning, so gave it a try (03:00 am in Athens at the moment…).
I get the same issue; thisOrderList is not parsed correctly as a list of mulitple items but rather as a list of 1 single item (the whole string is identified as 1 item).
So, when
set customerID to item 1 of thisOrderList
executes, the customerID becomes the whole order line.
The next command,

  set orderedPhotos to items 2 thru -1 of thisOrderList

results to an error -1728 as there are no items 2 etc. in the list.

I checked with another delimiter- instead of “;” but gives the same issue.

Thanks for any help,

Vangelis

Something is wrong with the format of your file then. Each entry has to be on a separate line… that’s where “paragraphs” breaks it all down into individual lines. Then each entry on each line has to be separated by a semi-colon and a space just like your example.

set fileText to "1; 50; 50; 128; 220
2; 140; 195; 210
3; 10; 10; 10"

set fileTextList to paragraphs of fileText
--> {"1; 50; 50; 128; 220", "2; 140; 195; 210", "3; 10; 10; 10"}

set {myTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, (";" & space)}

set anOrder to item 1 of fileTextList
set thisOrderList to text items of anOrder
--> {"1", "50", "50", "128", "220"}

set customerID to item 1 of thisOrderList
--> "1"

set orderedPhotos to items 2 thru -1 of thisOrderList
--> {"50", "50", "128", "220"}

The only other thing you might try is changing the first repeat loop like this…

repeat with i from 1 to count of fileTextList
	set thisOrderList to text items of (item i of fileTextList)
	set customerID to item 1 of thisOrderList
	
end repeat

Hank,

my bad! It took me reading your reply, to realise that applescript treats space as just another delimiter; in my mind spaces were ignored.
So, while the CSV file created through Excel didn’t have spaces, my example in the post had ones for better legibility.
I put as delimiter only a semicolon and now the parsing part works just fine.

What I am stuck with is the unique filename, though; while the first instance of jpg file is created OK (i.e. 1-50.jpg), I found out through debugging that
the statement
set f to (fDir & fName) as alias
always results to an error, so the function returns early (like this name doesn’t exist in the customers folder).

Any hints, there?

Thanks and best regards,

Vangelis

Hi Vangelis, I see the problem. It’s with this line inside the repeat loop. This is the line that errors and makes it jump out of the repeat loop early.

set idxNum to (text items -3 thru -1 of ("00" & idx)) as Unicode text

You can see we’re using “text items” and since we had changed applescript’s text item delimiters this line isn’t working properly. So I changed the subroutine to handle text item delimiters better, and also made a couple other minor changes. So use this as the subroutine now and all should be well!

-- this returns a unique name for an item in a particlar folder
-- this will check a folder (fDir) and see if it contains an item named fName.
-- If it does it will add a number onto the end of the name until that name does not exist in the folder
-- the number is separated from the name by the separator
on uniqueName(fDir, fName, separator)
	set {TIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ""}
	set fDir to fDir as text
	if fDir does not end with ":" then set fDir to fDir & ":"
	try
		set f to (fDir & fName) as alias
		set {name:Nm, name extension:Ex, kind:Knd} to info for f
		if Ex is missing value then set Ex to ""
		if Ex is not "" then set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
		set idx to 1
		repeat
			set idx to idx + 1
			set idxNum to text -3 thru -1 of ("00" & idx)
			
			if Knd is "Folder" then
				set checkName to (fName & separator & idxNum)
			else
				set checkName to (Nm & separator & idxNum & "." & Ex)
			end if
			try
				(fDir & checkName) as alias
			on error
				set AppleScript's text item delimiters to TIDs
				return checkName
			end try
		end repeat
	on error
		set AppleScript's text item delimiters to TIDs
		return fName
	end try
end uniqueName

One mistake in the whole script… not too bad! I hope that helps you out! :cool: How’s the weather in Greece anyway? I’ve never been there but coincidentally I may be going there later this summer to Rhodes.

Hi again Hank!

Thanks very much for the reply and the time you are taking to help!!! This is highly appreciated.

I substituted the uniqueName but still the problem persists; the script errors just after the try statement, when trying to set the alias (set f to (fDir & fName) as alias).
I checked the contents of both fDir and fName, they are OK.

Having said that, 1 single error in a script like that without actual debugging and testing, is more than fine; it is impressive!

Weather here is warm, as usual for the season, although we got some showers in the past couple of days.

You should come, the islands are just magnificent. I would strongly recommend though, if you travel down to Rhodes to take some time and visit some of the islands nearby - those are the Dodecanese as we call it, being twelve big islands. Sailing is the best way to do that; Patmos, Simi, Karpathos, Kalymnos are great destinations and are not so crowded as Rhodes can become during the summer. Let me know if you come eventually and I will provide more info on what is worth doing!

Best,

Vangelis

That is not making sense etsiot. I ran the script on my computer and it executes properly. If it is always erring on that line then the path you are feeding into the subroutine is malformed. You need to look at that path and make sure it looks good. There’s no other way it could be causing a problem.

One thing to check, at the top of the script where you define the folder locations… does the path to the customerPhotoFolder end in a colon “:”? It must end in a colon so that when we add the name of the file to the end of it that the entire path is formed properly.

Thanks for the tips on the islands. If I do end up going I’ll drop you an email for more information.

Try this script. In this script you have to pick the folders and files from choose dialog boxes. This way we know the paths will be correct. If you still have problems let me know. You first choose the originals folder, then you’ll choose the customers folder, then you’ll choose the CSV file. If this script runs properly then you know you have one of those variables defined wrong in the original script.


-- these are the variables you need to set
-- make sure the folder paths end in a colon ":"
--set originalPhotoFolder to (path to desktop folder as text) & "originals:"
--set customerPhotoFolder to (path to desktop folder as text) & "customers:" -- this is a folder which will contain the customer's ordered photos
--set fileText to read file ((path to desktop folder as text) & "orders.txt") -- this is the path to the CSV file containing the customer orders
set originalPhotoFolder to (choose folder with prompt "Choose the folder containing the original images.") as text
set customerPhotoFolder to (choose folder with prompt "Choose the folder where the customer images will be saved.") as text
set fileText to read (choose file with prompt "Choose the CSV file." without invisibles)


set fileTextList to paragraphs of fileText
set {myTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ";"}
try
	repeat with anOrder in fileTextList
		set thisOrderList to text items of anOrder -- now we have one line of the order in a list
		set customerID to item 1 of thisOrderList -- this is the customer number
		set orderedPhotos to items 2 thru -1 of thisOrderList -- this is a list of ordered photo numbers
		
		repeat with aPhoto in orderedPhotos
			-- calculate the original photo path
			set originalPhotoName to aPhoto & ".jpg"
			set originalPhotoPath to originalPhotoFolder & originalPhotoName
			
			-- calculate the copied photo's name
			set tempPhotoName to customerID & "-" & originalPhotoName -- get a temporary name for the copied photo
			set uniquePhotoName to uniqueName(customerPhotoFolder, tempPhotoName, "-") -- get a unique name for the file appending a number as necessary
			
			-- copy the original photo to the customers folder using the unique name
			do shell script "cp -p " & quoted form of POSIX path of originalPhotoPath & space & quoted form of POSIX path of (customerPhotoFolder & uniquePhotoName)
		end repeat
	end repeat
	
	-- clean up and alert the user
	set AppleScript's text item delimiters to myTID
	display dialog "Finished!" buttons {"OK"} default button 1 with icon note
on error theError number errorNumber
	set AppleScript's text item delimiters to myTID
	display dialog "There was an error:" & return & theError & return & return & "Error Number: " & errorNumber as text buttons {"OK"} default button 1 with icon stop
end try


(*=============== SUBROUTINES ===================*)
-- this returns a unique name for an item in a particlar folder
-- this will check a folder (fDir) and see if it contains an item named fName.
-- If it does it will add a number onto the end of the name until that name does not exist in the folder
-- the number is separated from the name by the separator
on uniqueName(fDir, fName, separator)
	set {TIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ""}
	set fDir to fDir as text
	if fDir does not end with ":" then set fDir to fDir & ":"
	try
		set f to (fDir & fName) as alias
		set {name:Nm, name extension:Ex, kind:Knd} to info for f
		if Ex is missing value then set Ex to ""
		if Ex is not "" then set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
		set idx to 1
		repeat
			set idx to idx + 1
			set idxNum to text -3 thru -1 of ("00" & idx)
			
			if Knd is "Folder" then
				set checkName to (fName & separator & idxNum)
			else
				set checkName to (Nm & separator & idxNum & "." & Ex)
			end if
			try
				(fDir & checkName) as alias
			on error
				set AppleScript's text item delimiters to TIDs
				return checkName
			end try
		end repeat
	on error
		set AppleScript's text item delimiters to TIDs
		return fName
	end try
end uniqueName

Hi again Hank,

I took your advise and checked again the actual path to the customers folder.
The POSIX name of the folder created the problem. When I put in the definition of customerPhotoFolder the name as alias (which actually includes the drive name in the path), the script runs perfectly.

You have saved me many hours of tedious and boring sorting through photos. If you ever come to Athens the drinks are on me! :slight_smile:

I will PM you my email. Feel free to drop a line whenever.

Best Regards,

Vangelis

PS: Just saw you last e-mail with the menus and everything! Sir, you are obliging! Thanks so much!

Wonderful! I’m glad we worked it out. Good luck and maybe we’ll get to meet, that would be cool. Later.