Your prescription for increased productivity and profitability
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.
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.
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.
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
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.)
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 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
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.
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
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
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.
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.
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.