Comparing modification dates of files within different folders

– Rephrasing the question

I didn’t get any responses from my question yesterday, so I conclude that I was overly complicated and just confused everyone. So let’s see if I can break it down simpler.

  1. I want to create a list of subfolders in multiple selected folders in the Finder.
  2. I want to create a list of files within each subfolder
  3. I want to compare the modification dates of files with the same name which are in the same named subfolders which may be in different selected folders.

For example, I have the following two files:
alias "Macintosh HD:Users:david.morgan:Documents:Collects:Job1:Images:cat.jpg
alias "Macintosh HD:Users:david.morgan:Documents:Collects:Job2:Images:cat.jpg

There are two files named “cat.jpg” but one is in Job1 and the other is in Job2. If I want to merge the folders Job1 and Job2, I want to first check that the modification dates for cat.jpg are the same. Otherwise I don’t want to merge them.

So my question is this - how do I make a list of files and associate them with a particular subfolder so I can later compare them to similarly named files in other subfolders? And by the way, I’m not asking for code, I just need the process!

Just ask the Finder for the items of each folder, and store the result somewhere.

You’re not getting many replies because, although you’ve outlined what you want, there are lots of issues you haven’t covered. Merge into where? What to do with unique subfolders? Howe deep are you traversing? There’s not really much to go on.

Thanks Shane, I’ll give you some more info.

I aim to merge all selected folders into one folder. The script needs to traverse to the full depth of all the subfolders and include every unique subfolder. For the subfolders that appear in more than one selected folder, they will be merged into the same place in the final folder… and the same goes for all of the subfolders within them…and the files they contain. However, this is all dependent on this preliminary check that all the files that will be merged must have the same modification date.

So the problem is I need a list of files for every subfolder. How do I organise where to store all these lists of files and how to associate them with the folders they are stored in?

You’re going to need to store them in lists of lists, or as records. There’s no magic solution; you’re going to have to do a fair bit of nested looping.

Before you do, it might be worth seeing if there’s a utility or command-line tool that does what you want.

Looking for a utility at this stage Shane is like a declaration of surrender. Never!

I like the idea of using records but I don’t know if its possible to create them on the fly like you can with lists. I mean, if I create a list within a loop, I can add it as an item to another list thus accumulate a list of lists. A record would be more useful because I could create one for each subfolder: each record could contain an alias address and a list of files. Is it possible to have a list inside a record? Is it possible to create records on the fly?

Yes and yes. It might be something like:

{folderPath:thePath, folderContents:{file1, file2, …}}

Thanks again Shane for clarifying “ so it is possible to store a list inside a record. But how would I create a record for each subfolder on the fly? The script will not know how many subfolders there will be so I can’t define the record variables at the start.

As an alternate to records I’ve got an idea now. I could create a list of subfolder addresses, then create a list of subfolder file lists. The order of the subfolder addresses would be the same as the order of the subfolder file lists. That way I can correlate the file lists to the subfolders.

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