Two Scripts, One Produces Text, the Other PDF

I have two scripts (originated here on MacScripter) as follows:

set theFolder to "MacBook HD:Users:homer:Documents:" as alias -- change path to desired value

set foldersAndFiles to getFoldersAndFiles(theFolder)
writeFile(foldersAndFiles)
on getFoldersAndFiles(theFolder)
	set foldersAndFiles to {theFolder as text}
	tell application "Finder"
		set theFiles to (name of every file in theFolder)
		if theFiles ≠ {} then set the end of foldersAndFiles to theFiles
		try
			set theFolders to (every folder of the entire contents of theFolder) as alias list
		on error
			set theFolders to {}
		end try
		repeat with aFolder in theFolders
			set contents of aFolder to aFolder as text
		end repeat
		set theFolders to sortFolders(theFolders) of me
		repeat with aFolder in theFolders
			set end of foldersAndFiles to linefeed & aFolder
			set theFiles to name of every file in folder aFolder
			if theFiles ≠ {} then set the end of foldersAndFiles to theFiles
		end repeat
	end tell
	set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
	set foldersAndFiles to foldersAndFiles as text
	set AppleScript's text item delimiters to ATID
	return foldersAndFiles
end getFoldersAndFiles

on writeFile(theText)
	set pdfMargins to 25
	set targetTextFile to (path to temporary items as text) & "MacBook Pro Documents.txt"
	set targetPdfFile to (path to desktop as text) & "MacBook Pro Documents.pdf"
	try
		set openedFile to (open for access file targetTextFile with write permission)
		set eof of openedFile to 0
		write theText to openedFile starting at eof
		close access openedFile
	on error
		try
			close access file targetTextFile
		end try
	end try
	do shell script "cupsfilter -D -o page-left=" & pdfMargins & " -o page-right=" & pdfMargins & " -o page-top=" & pdfMargins & " -o page-bottom=" & pdfMargins & " " & quoted form of POSIX path of targetTextFile & " > " & quoted form of POSIX path of targetPdfFile
end writeFile

on sortFolders(a)
	repeat with i from (count a) to 2 by -1
		repeat with j from 1 to i - 1
			if item j of a > item (j + 1) of a then
				set {item j of a, item (j + 1) of a} to {item (j + 1) of a, item j of a}
			end if
		end repeat
	end repeat
	return a
end sortFolders

And the second:

use framework "Foundation"
use scripting additions

set theFolder to "/Users/homer/Documents"
set theDays to 3
set theFiles to getFiles(theFolder, theDays)
set theFiles to formatFiles(theFiles) -- disable if desired
writeFile(theFiles)

on getFiles(theFolder, theDays)
	set fileManager to current application's NSFileManager's defaultManager()
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set dateKey to current application's NSURLContentModificationDateKey
	set regularFileKey to (current application's NSURLIsRegularFileKey) -- does not include packages
	set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects() -- excludes hidden files and package contents
	set filterDate to current application's NSDate's dateWithTimeIntervalSinceNow:(-86400 * theDays)
	set theFiles to current application's NSMutableArray's new()
	repeat with anItem in folderContents
		set {theResult, aDate} to (anItem's getResourceValue:(reference) forKey:dateKey |error|:(missing value))
		if (aDate's compare:filterDate) = 1 then -- use -1 to return older files
			set {theResult, aRegularFile} to (anItem's getResourceValue:(reference) forKey:regularFileKey |error|:(missing value))
			if aRegularFile as boolean is true then (theFiles's addObject:anItem)
		end if
	end repeat
	if theFiles's |count|() = 0 then display dialog "No matching files found" buttons {"OK"} cancel button 1
	set pathDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"stringByDeletingLastPathComponent" ascending:true selector:"localizedStandardCompare:" -- sort by path of containing folder
	set nameDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true selector:"localizedStandardCompare:" -- sort by file name
	return ((theFiles's valueForKey:"path")'s sortedArrayUsingDescriptors:{pathDescriptor, nameDescriptor})
end getFiles

on formatFiles(theFiles)
	set filePaths to theFiles's valueForKey:"stringByDeletingLastPathComponent"
	set fileNames to theFiles's valueForKey:"lastPathComponent"
	set formattedFiles to current application's NSMutableArray's arrayWithArray:{filePaths's objectAtIndex:0, fileNames's objectAtIndex:0}
	set oldFilePath to filePaths's objectAtIndex:0
	repeat with i from 1 to ((theFiles's |count|()) - 1)
		if ((filePaths's objectAtIndex:i)'s isEqualToString:oldFilePath) as boolean is false then
			(formattedFiles's addObjectsFromArray:{"", filePaths's objectAtIndex:i, fileNames's objectAtIndex:i})
		else
			(formattedFiles's addObject:(fileNames's objectAtIndex:i))
		end if
		set oldFilePath to (filePaths's objectAtIndex:i)
	end repeat
	return formattedFiles
end formatFiles

on writeFile(theFiles)
	set theString to theFiles's componentsJoinedByString:linefeed
	set theFolder to (current application's NSHomeDirectory()'s stringByAppendingPathComponent:"Desktop")
	set theFile to theFolder's stringByAppendingPathComponent:"Recent Documents.txt"
	theString's writeToFile:theFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeFile

I have tried changing the text producing script to a PDF producing script for the last couple of days, with no luck. And, my AppleScript skills are poor, so I have little idea how to do this other than cut & paste. Any help would be appreciated.

Homer. There were two issues. The variable theFiles needed to be made into a string. Also, the code in the writeFile handler that created a temporary file would not work. I don’t know the reason for that, so I substituted ASObjC code. The resulting script worked in limited testing on my Sonoma computer.

This script needs another look, and I’ll do that in a day or so. In the meantime, let me know of any issues.

use framework "Foundation"
use scripting additions

set theFolder to "/Users/Robert/Documents/" --set to desired value
set theDays to 30 --set to desired value
set theFiles to getFiles(theFolder, theDays)
set theFiles to formatFiles(theFiles) -- disable if desired
set theFiles to ((theFiles's componentsJoinedByString:linefeed) as text)
writeFile(theFiles)

on getFiles(theFolder, theDays)
	set fileManager to current application's NSFileManager's defaultManager()
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set dateKey to current application's NSURLContentModificationDateKey
	set regularFileKey to (current application's NSURLIsRegularFileKey) -- does not include packages
	set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects() -- excludes hidden files and package contents
	set filterDate to current application's NSDate's dateWithTimeIntervalSinceNow:(-86400 * theDays)
	set theFiles to current application's NSMutableArray's new()
	repeat with anItem in folderContents
		set {theResult, aDate} to (anItem's getResourceValue:(reference) forKey:dateKey |error|:(missing value))
		if (aDate's compare:filterDate) = 1 then -- use -1 to return older files
			set {theResult, aRegularFile} to (anItem's getResourceValue:(reference) forKey:regularFileKey |error|:(missing value))
			if aRegularFile as boolean is true then (theFiles's addObject:anItem)
		end if
	end repeat
	if theFiles's |count|() = 0 then display dialog "No matching files found" buttons {"OK"} cancel button 1
	set pathDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"stringByDeletingLastPathComponent" ascending:true selector:"localizedStandardCompare:" -- sort by path of containing folder
	set nameDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true selector:"localizedStandardCompare:" -- sort by file name
	return ((theFiles's valueForKey:"path")'s sortedArrayUsingDescriptors:{pathDescriptor, nameDescriptor})
end getFiles

on formatFiles(theFiles)
	set filePaths to theFiles's valueForKey:"stringByDeletingLastPathComponent"
	set fileNames to theFiles's valueForKey:"lastPathComponent"
	set formattedFiles to current application's NSMutableArray's arrayWithArray:{filePaths's objectAtIndex:0, fileNames's objectAtIndex:0}
	set oldFilePath to filePaths's objectAtIndex:0
	repeat with i from 1 to ((theFiles's |count|()) - 1)
		if ((filePaths's objectAtIndex:i)'s isEqualToString:oldFilePath) as boolean is false then
			(formattedFiles's addObjectsFromArray:{"", filePaths's objectAtIndex:i, fileNames's objectAtIndex:i})
		else
			(formattedFiles's addObject:(fileNames's objectAtIndex:i))
		end if
		set oldFilePath to (filePaths's objectAtIndex:i)
	end repeat
	return formattedFiles
end formatFiles

on writeFile(theText)
	set pdfMargins to 25
	set targetPdfFile to (path to desktop as text) & "Folder Contents.pdf"
	set targetTextFile to (current application's NSTemporaryDirectory())'s stringByAppendingPathComponent:"Folder Contents.txt"
	(current application's NSString's stringWithString:theText)'s writeToFile:targetTextFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
	set targetTextFile to targetTextFile as text
	do shell script "cupsfilter -D -o page-left=" & pdfMargins & " -o page-right=" & pdfMargins & " -o page-top=" & pdfMargins & " -o page-bottom=" & pdfMargins & " " & quoted form of POSIX path of targetTextFile & " > " & quoted form of POSIX path of targetPdfFile
end writeFile

Thank you!

For two days, I tried everything I could think of before finally posting here. And based on the two issues you mentioned, I really didn’t (with my limited skills) stand a chance. I also tried using the Shortcut you posted here that converts a file to a PDF.

In any event, this script works perfectly. Thank you again.

1 Like

I edited my script to correct a few issues. The only substantive change is that packages are now returned along with files. The timing result when run on my home folder ranged from 140 to 170 milliseconds, with the difference attributable to the value of the theDays variable (the greater the value the longer the timing result).

use framework "Foundation"
use scripting additions

on main()
	set theFolder to POSIX path of (choose folder)
	set theDays to 7 --set to desired value
	set theFiles to getFiles(theFolder, theDays)
	set folderTree to getFolderTree(theFiles)
	writeFile(folderTree)
end main

on getFiles(theFolder, theDays)
	set fileManager to current application's NSFileManager's defaultManager()
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set dateKey to current application's NSURLContentModificationDateKey
	set directoryKey to current application's NSURLIsDirectoryKey
	set packageKey to current application's NSURLIsPackageKey
	set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects() --option 6 skips hidden files and package contents
	set filterDate to current application's NSDate's dateWithTimeIntervalSinceNow:(-86400 * theDays)
	set theFiles to current application's NSMutableArray's new()
	repeat with anItem in folderContents
		set {theResult, aDate} to (anItem's getResourceValue:(reference) forKey:dateKey |error|:(missing value))
		if (aDate's compare:filterDate) = 1 then --1 is NSOrderedDescending
			set {theResult, aDirectory} to (anItem's getResourceValue:(reference) forKey:directoryKey |error|:(missing value))
			if (aDirectory as boolean) is false then
				(theFiles's addObject:anItem)
			else
				set {theResult, aPackage} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
				if (aPackage as boolean) is true then (theFiles's addObject:anItem)
			end if
		end if
	end repeat
	if theFiles's |count|() = 0 then display dialog "No matching files found" buttons {"OK"} cancel button 1
	set pathDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"stringByDeletingLastPathComponent" ascending:true selector:"localizedStandardCompare:"
	set nameDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true selector:"localizedStandardCompare:"
	return ((theFiles's valueForKey:"path")'s sortedArrayUsingDescriptors:{pathDescriptor, nameDescriptor})
end getFiles

on getFolderTree(theFiles)
	set fileTree to current application's NSMutableArray's new()
	set previousFolder to (theFiles's objectAtIndex:0)'s stringByDeletingLastPathComponent()
	fileTree's addObject:(previousFolder's stringByAppendingString:"/")
	repeat with aFile in theFiles
		set aFolder to aFile's stringByDeletingLastPathComponent()
		set aFileName to aFile's lastPathComponent()
		if (aFolder's isEqualToString:previousFolder) is false then
			(fileTree's addObject:"")
			(fileTree's addObject:(aFolder's stringByAppendingString:"/"))
			(fileTree's addObject:aFileName)
		else
			(fileTree's addObject:aFileName)
		end if
		set previousFolder to aFolder
	end repeat
	return ((fileTree's componentsJoinedByString:linefeed) as text)
end getFolderTree

on writeFile(theText)
	set pdfMargins to 25
	set targetTextFile to ((current application's NSTemporaryDirectory())'s stringByAppendingPathComponent:"Folder Contents.txt") as text
	set targetPdfFile to (((current application's NSHomeDirectory())'s stringByAppendingPathComponent:"Desktop")'s stringByAppendingPathComponent:"Folder Contents.pdf") as text
	(current application's NSString's stringWithString:theText)'s writeToFile:targetTextFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
	do shell script "cupsfilter -D -o page-left=" & pdfMargins & " -o page-right=" & pdfMargins & " -o page-top=" & pdfMargins & " -o page-bottom=" & pdfMargins & " " & quoted form of targetTextFile & " > " & quoted form of targetPdfFile
end writeFile

main()

I’m sure there are other changes, but this is the first one I’ve spotted:

on main()
	set theFolder to POSIX path of (choose folder)
	set theDays to 7 --set to desired value
	set theFiles to getFiles(theFolder, theDays)
	set folderTree to getFolderTree(theFiles)
	writeFile(folderTree)
end main

Which seems to work equally well when formatted both ways below.
This:

on main()
	set theFolder to POSIX path of "/Users/homer/Documents/" --set to desired value
	set theDays to 7 --set to desired value
	set theFiles to getFiles(theFolder, theDays)
	set folderTree to getFolderTree(theFiles)
	writeFile(folderTree)
end main

And this:

	set theFolder to "/Users/homer/Documents/" --set to desired value
	set theDays to 7 --set to desired value
	set theFiles to getFiles(theFolder, theDays)
	set folderTree to getFolderTree(theFiles)
	writeFile(folderTree)
end main

Is there a reason one would leave the “to POSIX path of” in the script?

“/Users/homer/Documents/” is already a POSIX path, so there’s no need to include “to POSIX path of” in the script. The second alternative is the correct one.

Thank you for the explanation, I also found other posts here that also helped with understanding.