UPDATING LINKED FILE NAMES

You have a document that is graphic-intensive, and now, for some reason, you have the need to update the names of the files linked to your document.

 

Not a difficult task, but time intensive if you have to do it one file at a time by hand.

Should you have the need, this blog post walks through the creation of a sample AppleScript to do the task for you automatically.

Even if you don’t see a specific need for this process, some of the code presented may be something you could use for some otherwise time-intensive tasks in the future.

The Script

Starting with the basics, we will assume that the user has a document with linked graphics open. The names of the linked files all contain a date stamp in the format YYYY-MM-DD. The script as written will find these date stamps and replace them with the current date. What we want at this point is a list of all of the links for graphics in the document. We can get this with the following code. Start a new AppleScript script and add the following:

tell application "Adobe InDesign CC 2018"
   tell document 1
	set linkList to item link of every image of every spline item
   end tell
end tell
linkList

Compile the script and run it with a sample document open. You should get a list of the links for the document in Script Editor’s Result window.

Repeat With Counting (Incrementing) Variable

Within a repeat loop we will process the links. A repeat with loop using a counting variable has the following general format where i is the incremented variable.

repeat with i from 1 to length of listVariable
set itemToProcess to item i of listVariable
--process itemToProcess
end repeat

To start (and for testing) we will work with just one item in the linkList. Add the following to the tell document 1 statement

--after set linkList to item link of every image of every spline item
repeat with i from 1 to 1
   set linkRef to item i of linkList
   set filePath to file path of linkRef
   set fileName to name of linkRef
   --process to change the file name 
end repeat

At the end of the code, test to see the value of filePath and fileName. The script should now read as follows:

tell application "Adobe InDesign CC 2018"
   tell document 1
	set linkList to item link of every image of every spline item
	repeat with i from 1 to 1
            set linkRef to item i of linkList
            set filePath to file path of linkRef
            set fileName to name of linkRef
            --process to change the file name 
         end repeat
   end tell
end tell
{filePath, fileName}

Now comes the fun part. We will need to have the Finder change the names for the files. First we will do a find/change to get the new file name.

At the top of the script, add variables to define the variables replaceString and useString. (You will need to change these values depending on the file names linked to your document.)

set replaceString to "2018-08-03"
set useString to "2018-08-05"

Below the comment –process to change the file name enter:

if fileName contains replaceString then
   set newName to my processName (fileName, replaceString, useString)
else
   set newName to "Replace string not found"
end if

Then at the bottom of the script add the following handler:

(*Uses text item delimiters to replace oldString with newString*)
on processName(fileName, oldString, newString)
	set AppleScript's text item delimiters to oldString
	set delims to text items of fileName
	set AppleScript's text item delimiters to newString
	set newName to delims as text
	set AppleScript's text item delimiters to ""
	return newName
end processName

Place the newName variable after the last end tell in your script just for testing. Compile and run the script. You should see the new name for the file in the Result window.

Change the File Name

Of course nothing happened if you ran the script at this point because the name of the file has not been changed. For this we will use the Finder. Add the following handler call immediately after the one above:

set newFilePath to my changeFileName (filePath, fileName, newName)

And at the bottom of the script add the handler:

(*Uses Finder to change the file name. Returns the path to the file using its new naame*)
on changeFileName(filePath, fileName, newName)
	set theOffset to offset of fileName in filePath
	set folderPath to text 1 thru (theOffset - 1) of filePath
	tell application "Finder"
		set oldFileRef to a reference to file filePath
		set name of oldFileRef to newName
	end tell
	return folderPath & newName
end changeFileName

Test

If you now run the script, you will see one of your images is displaying the Missing File badge because the file name has been changed. (You will need to update this image by hand.)

The Last Step

We now add code to have InDesign update the file path for the link where its file name has changed. After the call to the changeFileName handler, add:

relink linkRef to file newFilePath

If you look in the code above, the reference for linkRef is item i of linkList which can only be the first item in the list. To test the script further, you can change the repeat with statement to read:

repeat with i from 2 to 2

Or you can change it to process all of the files in the linkList.

repeat with i from 1 to length of linkList
--statements here
end repeat

The Raw Script

The script should now read as follows: Of course you will need to add the handlers from above to complete.

set replaceString to "2018-08-03"
set useString to "2018-08-05"

tell application "Adobe InDesign CC 2018"
   tell document 1
	set linkList to item link of every image of every spline item
	repeat with i from length of linkList to 1 by -1
	   set linkRef to item i of linkList
	   set filePath to file path of linkRef
	   set fileName to name of linkRef
	   --process to change the file name 
	   if fileName contains replaceString then
		set newName to my processName(fileName, replaceString, useString)
		set newFilePath to my changeFileName(filePath, fileName, newName)
		relink linkRef to file newFilePath
	   --we have removed the newName else test
	   end if
	end repeat
   end tell
end tell
newFilePath

--Add the following handlers: processName and changeFileName and test

Making the Script User Friendly

Unless you are the only user of the script and you don’t mind changing the two variables at the top of the script, you will want to make the script user friendly. For simplicity we can get the current date (useString) from the computer.

Date Stamp

Start a new script just for testing, and add the following:

set dateString to getDateStamp()
dateString

(*Returns current date in form YYYY-MM-DD*)
on getDateStamp()
   set d to (current date)
   copy d to b
   set month of b to January
   set theMonth to (text -2 thru -1 of ("0" & (1 + ((d - b + 1314864) div 2629728)) as string))
   set theDay to (text -2 thru -1 of ("0" & day of d as string))
   set theYear to (year of d as string)
   return theYear & "-" & theMonth & "-" & theDay
end getDateStamp

Display Dialog

Similarly, start a new test script to get the user to define the text to be replaced in the file names. We could use a grep expression to replace any date in our subject file names list with the current date, but we will reserve that for a later blog post. For now we will use a display dialog to have the user enter the target string (replaceString).

set thePrompt to "Enter date to change in the following format YYYY-MM-DD"
set theTitle to "String to Replace"
set minLength to 10
try
   set replaceString to getUserResponse(thePrompt, theTitle, minLength)
on error errStr
   activate
   display alert "Error " & errStr
end try

(*Returns text entered by user in display dialog. Adds test for minimum string length*)
on getUserResponse(thePrompt, theTitle, minLength)
   set userResponse to display dialog thePrompt default answer "" with title theTitle buttons {"OK", " Cancel"} default button 1
   if button returned of userResponse is " Cancel" then
	error "User cancelled"
   else if length of text returned of userResponse < minLength then
	error "Text entered is empty or not correct format"
   else
	return text returned of userResponse
   end if
end getUserResponse

Bullet Proofing

Notice the try/on error/end try statement block in the call to this handler. Any time there is a possibility of the user cancelling out of a script or entering inproper information your wcripts will need to surround the potentially error-prone statements with a try/on error/end try erroor trap. This way, the script can exit gracefully while giving the user a reason why. You might want to experiment with the Display Dialog code above.

We can also put an error trap around the entire top portion of the script to catch any errors that may be generated.

Put it all together

Replace the hard-coded definitions for replaceString and useString at the top with calls to the handlers:

set thePrompt to "Enter date to change in the following format YYYY-MM-DD"
set theTitle to "String to Replaace"
set minLength to 10
try
   set replaceString to getUserResponse(thePrompt, theTitle, minLength)
on error errStr
   activate
   display alert "Error " & errStr
end try
set useString to getDateStamp()

Adding an error trap to the top portion of the script, it now reads as follows:

set thePrompt to "Enter date to change in the following format YYYY-MM-DD"
set theTitle to "String to Replace"
set minLength to 10
try
   set replaceString to getUserResponse(thePrompt, theTitle, minLength)
on error errStr
   activate
   display alert "Error " & errStr
   return
end try
set useString to getDateStamp()

try
tell application "Adobe InDesign CC 2018"
   tell document 1
	set linkList to item link of every image of every spline item
	repeat with i from length of linkList to 1 by -1
	   set linkRef to item i of linkList
	   set filePath to file path of linkRef
	   set fileName to name of linkRef
	   --process to change the file name 
	   if fileName contains replaceString then
		set newName to my processName(fileName, replaceString, useString)
		set newFilePath to my changeFileName(filePath, fileName, newName)
		relink linkRef to file newFilePath
	   end if
	end repeat
   end tell
end tell
on error errStr
   activate
   display alert "Error " & errStr
end try 

Be sure to add the handlers and you should have a fairly useable script.

ABOVE AND BEYOND

Think about instances where you could modify the code above to take care of an issue with linked graphic files. If you have’t done so already, start a folder of script handlers that you may want to use or modify for scripts in the future. For sure the getDateStamp() and getDateStamp() handlers have some great potential.