experimental script to merge selected items into pdf & m

Dear all,

here’s another applescript I’ve been tinkering with for a while and seems to mostly work, so I thought I’d share, and mention what seems to be one bug.

What it does: the script assumes you have selected multiple items in devonthink. When you run the script, it will then “print” these items to a virtual pdf printer, merge them into a single pdf, and then ship the merged file as an attachment to apple’s mail program. It would be easy to modify this to send the file back to devonthink.

What you need to know before even trying to use this: The script requires that you install a printer extension called “cups-pdf” which basically emulates a printer, but outputs pdf files. The download link to this program is mentioned in the script. It expects furthermore that you configure that set up as suggested in the script. You should set your printer name to “PDF Writer”. If you use a different printer name or use a different output directory other than the default (=~/Desktop/cups-pdf/), you should change the script accordingly.

Bugs: as far as I can tell, devonthink ignores the “target printer” directive to its print command. Until this works differently (maybe I’m doing something wrong, maybe it is devon think), the script has to work by changing your printer by scripting the Printer Setup Utility. This isn’ so bad, but if the script fails, your default printer might need to be changed back to your original setting.

I think it is fair to say that in the long run, it would be really cool if devonthink had a “convert window to pdf” applescript command like devonagent’s menu command to output a pdf. That would obviate the need for installing a separate print extension and thus most of the unpredictability of this script.

But since for me this is one of my most valuable extensions to devon think, because it allows one to “share” clippings, no matter what they are, with other people, and it allows me to aggregate pictures and text into a single pdf, I hope that despite its quirks, some of you will find it useful and post feedback here. It could be debugged and cleaned up further if there is interest.

cheers,

Eric


-----Merge selected items to  single pdf, mail pdf
----Requires the cups-pdf back-end to be installed. Its printer should be configured as "PDF Writer" or the variable below should be changed.

---- For downloading cups-pdf see  http://www.codepoetry.net/projects/cups-pdf-for-mosx

property output_file : "news-links.pdf"
property max_idle : 200
property cups_printer_name : "PDF Writer"

property error_log_level : 3
property error_log : ((path to desktop) as text) & "Script Error.log"
property write_to_error_log : false ---sets debugging to write to file below (great if running from script menu)
my write_error_log("start script…" & (name of me) & ((current date) as string), 1)


---this gets the full home directory. I'm sure there is a more applescript way of doing this, but this 
set the_path to do shell script ("echo $HOME")
set cups_pdf_directory to the_path & "/Desktop/cups-pdf/"

---the following variable points to os x 10.4's join.py script which is part of Apple's automator.  Obviously, you need 10.4 for this to work
set merge_pdf_command to "python '/System/Library/Automator/Combine PDF Pages.action/Contents/Resources/join.py' -o " & cups_pdf_directory & output_file & "  "

---alternative command for those who have ghostscript installed.  (see fink.sourceforge.org) 
---property merge_pdf_command : "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=" & cups_pdf_directory & output_file


-----this next block of code is necessary until we figure out why devon think does not accept the "print settings" parameter to the print command
set found_cups_printer to false
set pdf_list to {}
tell application "Printer Setup Utility"
	set printer_list to printers
	set original_printer to current printer
	repeat with this_printer in printer_list
		if name of this_printer is cups_printer_name then set found_cups_printer to true
	end repeat
	if found_cups_printer is false then
		display dialog "This script requires you to install the package cups-pdf. Have you installed and configured cups-pdf so that there is a printer named \"" & cups_printer_name & "\"  ?  At the moment I could not find it in your printer list." with cancel button
		return
	end if
	if name of current printer is not cups_printer_name then
		set current printer to printer cups_printer_name
	end if
end tell


try
	do shell script ("mv  " & cups_pdf_directory & "* ~/.Trash/")
end try
tell application "DEVONthink Pro"
	set names_printed to {}
	set cuPos to selection of front window
	
	
	if cuPos is {} then
		display dialog "This script expects that you have multiple items selected.  Please select multiple items and try script again."
		return
	end if
	
	set props to {target printer:cups_printer_name}
	repeat with this_item in cuPos
		if ((filename of this_item) as string) ends with ".PDF" then
			set pdf_list to pdf_list & {"\"" & cups_pdf_directory & (filename of this_item) & "\""}
			export record this_item to cups_pdf_directory
		else
			set temp_window to open window for record this_item
			set visible of temp_window to false
			repeat while loading of temp_window
				delay 1
			end repeat
			
			print temp_window with properties props without print dialog
			set the_name to name of temp_window
			set names_printed to names_printed & {"_" & (the_name) & "_"}
			close temp_window
		end if
	end repeat
end tell
my write_error_log("delaying while are put through cups-pdf.....", 4)
tell application "Printer Setup Utility"
	using terms from application "Printer Setup Utility"
		set the_count to 1
		set times_idle to 0
		repeat
			delay 3
			set the_count to the_count + 1
			set the_status to (status of printer cups_printer_name) as string
			
			my write_error_log("printer is  " & the_status, 4)
			
			if (the_status) contains "idle" then
				set times_idle to times_idle + 1
				my write_error_log("printer idle #" & times_idle as string, 4)
			else
				set times_idle to 0
			end if
			if (times_idle is greater than 2) then exit repeat
			if (the_count) is greater than max_idle then
				error ("It seems like it is taking too long to do print jobs....")
				my reset_printer(original_printer)
				return
			end if
		end repeat
	end using terms from
end tell
my write_error_log("resetting printer", 4)

my reset_printer(original_printer)

log names_printed as string
set shell_cmd to merge_pdf_command
repeat with this_pdf_file in names_printed
	log this_pdf_file as Unicode text
	---this is a bit gross, but I have reverse engineered the character substitutions that cups-pdf places on the files when printed.  it is likely that a few more need to be added.... 
	set shell_cmd to shell_cmd & "" & cups_pdf_directory & my replace_these_chars_with_this_one(this_pdf_file, {{"\"", "_"}, {" ", "_"}, {",", "_"}, {":", "_"}, {"[", "_"}, {"]", "_"}, {"—", "_342_200_224"}, {"\"", "__"}, {"(", "__"}, {")", "__"}, {"}", "_"}, {"&", "_"}, {".", "_"}, {"'", "_"}, {"/", "_"}, {"|", "_"}, {"?", "_"}}) & ".pdf  "
end repeat

repeat with this_pdf in pdf_list
	set shell_cmd to shell_cmd & " " & this_pdf
end repeat

---shell_cmd to merge_pdf_command & cups_pdf_directory & "*"
try
	my write_error_log("python command  was: " & shell_cmd & "
	It returned: ", 4)
	do shell script (shell_cmd)
	my write_error_log(result, 2)
	---my write_error_log(merge_results, 4)
	
on error err_message
	my write_error_log(err_message, 2)
	set shell_cmd to "rm " & cups_pdf_directory & output_file & ";" & merge_pdf_command & cups_pdf_directory & "*"
	set merge_results to do shell script (shell_cmd)
	my write_error_log("had to use wildcard : " & merge_results, 4)
end try


---comment out the block of code below if you don't want the script to send the file as an attachment to a mail message.
tell application "Mail"
	set newMessage to (a reference to (make new outgoing message))
	
	tell newMessage
		make new recipient at beginning of to recipients ¬
			with properties {address:"someone@somewhere.com"}
		
		set the subject to "PDF of links"
		set the content to "Dear , 
		Here's a pdf containing the clippings I was telling you about.  
		
		best, 
		
		me
		
		"
		
		tell content
			make new attachment ¬
				with properties {file name:cups_pdf_directory & output_file} ¬
				at after the last word of the last paragraph
		end tell
		
		set visible to true
	end tell
end tell


---comment out the block of code below if you don't want it to reimport the pdf to devonthink.
tell application "DEVONthink Pro"
	import (cups_pdf_directory & output_file)
end tell


on reset_printer(original_p)
	tell application "Printer Setup Utility"
		set current printer to original_p
	end tell
end reset_printer


on replace_these_chars_with_this_one(this_text, list_of_replacements)
	---set list_of_replacements to every item in list_of_replacements
	repeat with this_pair in list_of_replacements
		set this_text to my replace_chars(this_text, first item of this_pair, second item of this_pair)
	end repeat
	return this_text
end replace_these_chars_with_this_one

on replace_chars(this_text, search_string, replacement_string)
	set AppleScript's text item delimiters to the search_string
	set the item_list to every text item of this_text
	set AppleScript's text item delimiters to the replacement_string
	set this_text to the item_list as string
	set AppleScript's text item delimiters to ""
	return this_text
end replace_chars



on write_error_log(this_error, verbosity_level_of_this_item)
	
	if verbosity_level_of_this_item is greater than error_log_level then return
	if write_to_error_log then
		try
			open for access file the error_log with write permission
			write (this_error & return) to file the error_log starting at eof
			close access file the error_log
		on error
			try
				close access file the error_log
			end try
		end try
	else
		log this_error
	end if
end write_error_log


The code has been updated now with several improvements since thie initial post. It’s still experiemental, but new & improved & extra crispy…
eric

The print settings-parameter is not yet supported but probably a future version will support this.