Hi all,
just wanted to check back and let you know I finished the script that merges multiple folders in the finder. If you want to try it, copy the following code and save the script as an app. Drag the app into the tool bar so you can activate it with one click. Select the folders you want to merge in the Finder (in the same Finder window) and click on the app icon in the toolbar. Otherwise you can drag and drop them to the app or alias.
I’ve designed this to merge any number of folders and keep the folder hierarchy. It does a preliminary check to see if there are duplicate files which would end up in the same combined folder (or subfolder). If the files are of the same modification date, it will go ahead with the merge, if not, the script will create a report and ask you whether you want to continue. It’s a pretty simple folder merger which gives you the option of either merging or aborting.
I originally wanted to use this for folders collected by Indesign. When you collect multiple files, the collected folders often end up containing the same links and the folders can be merged to save space and reduce time taken to upload them to a printer for example. So I’ve arranged the script to also file PDFs and IDML files into appropriately named subfolders. The script also ignores the modification dates of text files called “Instructions.txt” (which may be reports created by Indesign), and font files.
In terms of process, after being advised by Shane, I used the lists of lists model to compile lists of file names and file aliases to compare names and modification dates. I’m sure the script could be more efficient but it does work!
--Open handler in case of drag and drop
on open these_items
DoProcess(these_items)
end open
--On run handler in case of selection and click icon of app
--on run
--Variables
global AliasList
global NameList
global NameList2
global AliasList2
set {AliasList, NameList, ModList} to {{}, {}, {}}
global FolderBranchList
global FolderAliasList
--
global FolderFileBranchList
global FolderFileAliasList
--
global TopLevelFileBranchList
global TopLevelFileAliasList
--
global BigKahunaBranchList
global BigKahunaAliasList
set {FolderBranchList, FolderAliasList, FolderFileBranchList, FolderFileAliasList, TopLevelFileBranchList, TopLevelFileAliasList, BigKahunaBranchList, BigKahunaAliasList} to {{}, {}, {}, {}, {}, {}, {}, {}}
--
global TopLevelDepth
set these_items to {}
--GET THE SELECTION
tell application "Finder"
set selection_list to the selection
end tell
-- CHECK THAT SOMETHING IS SELECTED
if selection_list is {} or (count of selection_list) < 2 then
display dialog "This script merges collected folders. Please select some folders and try again."
return
end if
-- CONVERT EACH ITEM TO AN ALIAS
repeat with i from 1 to the count of selection_list
set ThisItem to item i of selection_list as alias
--CHECK SELECTION ONLY CONTAINS FOLDERS
set MyFileInfo to info for ThisItem
if folder of MyFileInfo is false then
display dialog "This script merges collected folders. Please select some folders (not files) and try again."
return
end if
--
set these_items to these_items & ThisItem
end repeat
DoProcess(these_items)
--end run
on DoProcess(these_items) --THIS IS THE LIST OF PROCESSES
--1. Get top level folder depth - this is the same for every selected folder
set ExampleSelectedFolder to item 1 of these_items
set ExampleSelectedFolder to ExampleSelectedFolder as text
set AppleScript's text item delimiters to ":"
set TopLevelDepth to (count of text items in ExampleSelectedFolder)
set AppleScript's text item delimiters to ""
--2.
display dialog "Welcome to the folder merger." & return & return & "Creating a list of every subfolder..." giving up after 2
repeat with ThisFolder in these_items
set FolderStem to ThisFolder as text
set FolderStemLength to length of FolderStem --How many characters in folder address.
CreateFolderList(ThisFolder, FolderStemLength)
CreateTopLevelFileList(ThisFolder, FolderStemLength)
end repeat
--3.
display dialog "Creating a list of every file in every subfolder..." giving up after 2
repeat with ThisFolder in FolderAliasList
CreateFolderFileLists(ThisFolder)
end repeat
--4.
set {ErrorReport, DateListCount} to CheckDuplicates()
if DateListCount > 1 then
if DateListCount < 20 then
display dialog "Duplicate items with the same modification date have been found:" & return & return & ErrorReport & return & "Whadyawannado?" buttons {"Carry on regardless", "Bail out now"} default button 2
if button returned of result is "Bail out now" then return
else
tell application "TextEdit"
activate
if (count of every document) is not 0 and text of document 1 is "" then close document 1
set MyDocument to make new document
set the bounds of window 1 to {421, 266, 1707, 1093}
set text of document 1 to ErrorReport
delay 1
display dialog "Error report has been generated. Do you want to stop and review or continue?" buttons {"Continue", "Stop and review"} default button 2
if button returned of result is "Stop and review" then
return
else
tell application "TextEdit" to close document 1 saving no
end if
end tell
end if
else
display dialog "No duplicates with different modification dates were found." giving up after 2
end if
--5. Make a new folder in parent folder
set MergedFolder to CreateNewFolder(these_items)
--6. Move top level files into the new folder
repeat with ThisFolder in these_items
MoveStuffTopLevelFiles(ThisFolder, MergedFolder)
end repeat
--7 Move top level files into PDF and IDML folders if required
tell application "Finder"
set TopLevelList to every file in folder MergedFolder
repeat with ThisFile in TopLevelList
set ItemKind to kind of ThisFile
if ItemKind is in {"Adobe InDesign CC 2015 Document", "Adobe InDesign CC 2014 Document"} then
--Check if it's an indd or an idml
set ItemExtension to name extension of ThisFile
if ItemExtension is "indd" then
set FolderTarget to ""
else
set FolderTarget to "IDML_files:"
if not (exists folder "IDML_files" in folder MergedFolder) then make new folder at MergedFolder with properties {name:"IDML_files"}
end if
else if ItemKind is "Portable Document Format (PDF)" then
set FolderTarget to "PDFs:"
if not (exists folder "PDFs" in folder MergedFolder) then make new folder at MergedFolder with properties {name:"PDFs"}
else
set FolderTarget to ""
end if
set MoveItemTarget to MergedFolder & FolderTarget
move ThisFile to MoveItemTarget -- with replacing
end repeat
end tell
--8. Create new folder branches in the new folder
repeat with ThisBranch in FolderBranchList
CreateNewBranches(ThisBranch, MergedFolder)
end repeat
--9. Move files into folder branches with replacing
repeat with ThisFolderNumber from 1 to count of FolderBranchList
set ThisFolderBranch to item ThisFolderNumber of FolderBranchList
set NewAliasFolder to (MergedFolder & ThisFolderBranch) as alias
repeat with OldAlias in (item ThisFolderNumber of FolderFileAliasList)
tell application "Finder" to move OldAlias to NewAliasFolder with replacing
end repeat
end repeat
--10. Delete original folders
repeat with ThisFolder in these_items
tell application "Finder" to delete ThisFolder
end repeat
--11. Display finished message
tell application "Finder"
display dialog "Selected folders have been merged."
end tell
end DoProcess
on CreateFolderList(ThisFolder, FolderStemLength)
tell application "Finder" to set FolderItems to every item in ThisFolder
repeat with ThisItem in FolderItems
set ThisItem to ThisItem as alias
tell application "Finder" to set ThisItemKind to kind of ThisItem
if ThisItemKind is "folder" then
set the end of FolderAliasList to ThisItem
set ThisItemBranch to ThisItem as text
set ThisItemBranch to text (FolderStemLength + 1) thru (length of ThisItemBranch) of ThisItemBranch
set the end of FolderBranchList to ThisItemBranch
CreateFolderList(ThisItem, FolderStemLength)
end if
end repeat
end CreateFolderList
on CreateTopLevelFileList(ThisFolder, FolderStemLength)
tell application "Finder" to set FolderItems to every item in ThisFolder
repeat with ThisItem in FolderItems
set ThisItem to ThisItem as alias
tell application "Finder" to set ThisItemKind to kind of ThisItem
if ThisItemKind is not "folder" then
set ThisItemBranch to ThisItem as text
set the end of TopLevelFileAliasList to ThisItem
set ThisItemBranch to text (FolderStemLength + 1) thru (length of ThisItemBranch) of ThisItemBranch
set the end of TopLevelFileBranchList to ThisItemBranch
end if
end repeat
end CreateTopLevelFileList
on CreateFolderFileLists(ThisFolder)
set ThisFolderList1 to {}
set ThisFolderList2 to {}
tell application "Finder" to set AllItems to every item in ThisFolder
repeat with ThisItem in AllItems
set ThisItem to ThisItem as alias
tell application "Finder" to set ThisItemKind to kind of ThisItem
if ThisItemKind is not "folder" then
set the end of ThisFolderList1 to ThisItem
--Get item branch from top level folder
set ThisItemBranch to ""
set ThisItem to ThisItem as text
set AppleScript's text item delimiters to ":"
repeat with i from TopLevelDepth to (the count of text items in ThisItem)
set ThisItemBranch to ThisItemBranch & (text item i of ThisItem)
if i is not (the count of text items in ThisItem) then set ThisItemBranch to ThisItemBranch & ":"
end repeat
set AppleScript's text item delimiters to ""
set the end of ThisFolderList2 to ThisItemBranch
set the end of BigKahunaBranchList to ThisItemBranch
set the end of BigKahunaAliasList to (ThisItem as alias)
end if
end repeat
set the end of FolderFileAliasList to ThisFolderList1
set the end of FolderFileBranchList to ThisFolderList2
end CreateFolderFileLists
on CreateNewFolder(these_items)
tell application "Finder"
set ParentDirectory to (container of item 1 of these_items) as alias
set DesiredName to "Merged_Folder"
set MergedFolder to (ParentDirectory as text) & DesiredName & ":"
if exists MergedFolder then
set FolderCounter to 0
repeat
set FolderCounter to FolderCounter + 1
set FolderCounterName to FolderCounter as text
set MergedFolder to (ParentDirectory as text) & DesiredName & "_" & FolderCounterName & ":"
if not (exists MergedFolder) then exit repeat
end repeat
set DesiredName to DesiredName & "_" & FolderCounterName
end if
make new folder at ParentDirectory with properties {name:DesiredName}
end tell
return MergedFolder
end CreateNewFolder
on CheckDuplicates()
set ErrorReport to return & "THIS SCRIPT ADVISES - DO NOT GO AHEAD WITH THE MERGE; THERE ARE INSTANCES OF FILES WITH THE SAME FILENAME HAVING DIFFERENT MODIFICATION DATES AND FILE SIZE." & return
set {ItemBranch2, ReportList} to {{}, {}}
set DateListCount to 0
repeat with i from 1 to the length of BigKahunaBranchList
set DraftDateListCount to 0
set ThisItemBranch to item i of BigKahunaBranchList
set ModDiffFlag to false
set DraftReport to ""
if ThisItemBranch is not in ReportList and ThisItemBranch is in ItemBranch2 then
tell application "Finder"
set ThisFileName to the name of item i of BigKahunaAliasList
set ThisKind to the kind of item i of BigKahunaAliasList
set ThisModDate to modification date of item i of BigKahunaAliasList
set ThisFileSize to size of item i of BigKahunaAliasList
end tell
if ThisKind is not in {"PostScript® OpenType® font", "TrueType® OpenType® font"} and ThisFileName is not "Instructions.txt" and ThisFileName does not contain "AdobeFnt" then
set DraftReport to DraftReport & return & "Item name: " & ThisFileName & return
repeat with j from 1 to count of BigKahunaBranchList
set ItemJ to item j of BigKahunaBranchList
if ItemJ is ThisItemBranch then
tell application "Finder"
set J_ModDate to (modification date of item j of BigKahunaAliasList) as text
set J_FileSize to size of item j of BigKahunaAliasList
end tell
set DraftReport to DraftReport & J_ModDate & " " & tab & "Size: " & J_FileSize & " KB" & return
set DraftDateListCount to DraftDateListCount + 1
if J_ModDate is not ThisModDate and J_FileSize is not ThisFileSize then set ModDiffFlag to true
end if
end repeat
end if
else
set the end of ItemBranch2 to ThisItemBranch
end if
if ModDiffFlag is true then
set ErrorReport to ErrorReport & DraftReport
set DateListCount to DateListCount + DraftDateListCount
end if
end repeat
return {ErrorReport, DateListCount}
end CheckDuplicates
on list_position(this_item, this_list)
repeat with i from 1 to the count of this_list
if item i of this_list is this_item then return i
end repeat
return 0
end list_position
on MoveStuffTopLevelFiles(ThisFolder, MergedFolder)
set MergedFolder to MergedFolder as alias
tell application "Finder"
set FolderList to every item in folder ThisFolder
repeat with ThisItem in FolderList
set ThisItem to ThisItem as alias
set ItemKind to kind of ThisItem
if ItemKind is not "folder" then move ThisItem to MergedFolder with replacing
end repeat
end tell
end MoveStuffTopLevelFiles
on CreateNewBranches(ThisBranch, MergedFolder)
set BranchFolderList to ConvertAliasToList(ThisBranch)
set MyTestFolder to MergedFolder
set FolderDepth to count of BranchFolderList
repeat with i from 1 to (FolderDepth - 1)
set ThisFolder to item i of BranchFolderList
CheckForFolder(MyTestFolder, ThisFolder)
set MyTestFolder to ((MyTestFolder as text) & ThisFolder & ":") as alias
end repeat
end CreateNewBranches
on CheckForFolder(ParentFolder, TargetFolder)
set ParentFolder to ParentFolder as alias
tell application "Finder"
if not (exists folder TargetFolder of ParentFolder) then
make new folder at ParentFolder with properties {name:TargetFolder}
end if
end tell
end CheckForFolder
on ConvertAliasToList(MyTarget)
set MyTarget to MyTarget as text
set AppleScript's text item delimiters to ":"
set MyTargetList to every text item of MyTarget
set AppleScript's text item delimiters to ""
return MyTargetList
end ConvertAliasToList