Script: Create "Summarize Highlights" TSV for import into Tinderbox

This script creates TSV records from “Summarize Highlights” of PDF(s) for import into Tinderbox.

It can be used with the “Summarize Highlights”'s Markdown output of one or more selected PDF(s).

What’s included:

  • Source PDF name
  • Annotation
  • Annotation details
  • Page
  • Page item link

Usage:

  • Select one or more PDF(s).
  • Menu Tools > Summarize Highlight > as Markdown
  • Select the Markdown record(s)
  • Run script
  • Drag the TSV(s) to desktop
  • Drag the TSV(s) into Tinderbox
  • Use stamp 1

How it works:

Stamp 1

Tinderbox doesn’t support new lines inside a TSV field. In order to keep the original layout of an annotation’s details the script replaces new lines with " ---LINEFEED--- ". In Tinderbox this placeholder has to be replaced back into a linefeed. It’s also necessary to replace doubled double quotes. To make things easier the clipboard is automatically set to the necessary stamp code.

To rebuild the layout use stamp 1:

$Name=$Name.replace('\"\"','\"');
$SourcePDF=$SourcePDF.replace('\"\"','\"');
$Annotation=$Annotation.replace('\"\"','\"');
$Details=$Details.replace('\"\"','\"').replace(" ---LINEFEED--- ","\n");
$Text=$Text.replace('\"\"','\"').replace(" ---LINEFEED--- ","\n");

Stamp 2 (optional)

The script supports the creation of TSVs from the “Summarize Highlights” output of one or more selected PDFs. In case you’ve used menu “Summarize Highlights” with more than one selected PDF you’ll get the annotations etc. but they are not grouped into Tinderbox container as it would be if you only had selected one PDF when using “Summarize Highlights” . So moving each annotation in a container with the source PDF’s name might be necessary.

To group annotation notes use stamp 2:

$Container=$Container+$SourcePDF;

Prototype (optional)

In case you want to apply a Prototype to the imported annotation notes:

The import process sets the $KeyAttributes locally for all notes it creates. Thus if you apply a prototype using key attributes to the newly created notes, the Key Attributes will not show in the inheriting notes as the local values unless/until you reset the $KeyAttributes for these notes.
A Tinderbox Reference File - Spreadsheet (Tab-Delimited Text) Import

To reset KeyAttributes use this stamp:

$KeyAttributes=;

If you have questions please don’t hesitate to ask.

-- Create "Summarize Highlights" TSV for import into Tinderbox

-- In DEVONthink: With one or more selected PDF(s): menu "Tools > Summarize Highlight > as Markdown"
-- Select resulting Markdown record(s)
-- Run script
-- Drag resulting TSV(s) into Finder, e.g. desktop
-- In Finder: Drag TSV(s) into Tinderbox
-- In Tinderbox: Use at least the first stamp (it's copied automatically)

(* Use the first stamp to rebuild double quotes and linefeeds:

$Name=$Name.replace('\"\"','\"');
$SourcePDF=$SourcePDF.replace('\"\"','\"');
$Annotation=$Annotation.replace('\"\"','\"');
$Details=$Details.replace('\"\"','\"').replace(" ---LINEFEED--- ","\n");
$Text=$Text.replace('\"\"','\"').replace(" ---LINEFEED--- ","\n");

Optionally: Use the second stamp to group annotation notes:

$Container=$Container+$SourcePDF;

*)

tell application id "DNtp"
	try
		set theRecords to selected records
		if theRecords = {} then error "Please select some \"Summarize Highlights\" Markdown records"
		set theOutputGroup to display group selector "Choose output group:"
		show progress indicator "Creating TSV... " steps (count theRecords) as string with cancel button
		
		repeat with thisRecord in theRecords
			set theType to (type of thisRecord) as string
			if theType is in {"markdown", "«constant ****mkdn»"} then
				step progress indicator "... " & (name of thisRecord) as string
				set theText to plain text of thisRecord
				set theParagraphs to paragraphs of theText
				set theParagraphs_count to (count theParagraphs)
				set the_record to {}
				set thisAnnotation_Details to {}
				
				repeat with i from 1 to theParagraphs_count
					set thisParagraph to (item i in theParagraphs) as string
					set thisParagraph to my trimEnd(thisParagraph)
					if thisParagraph begins with "# " then
						set thisPDF_UUID to characters ((offset of "](x-devonthink-item://" in thisParagraph) + 22) thru -2 in thisParagraph as string
						set thisPDF to (get record with uuid thisPDF_UUID)
						set thisPDF_Name to my recordName(name of thisPDF, filename of thisPDF)
						if thisPDF_Name contains "/" then set thisPDF_Name to my replaceString(thisPDF_Name, "/", "-")
						set finish to false
					else if thisParagraph begins with "## [Page " then
						set thisPageRefURL to (characters ((offset of "](" in thisParagraph) + 2) thru -2 in thisParagraph) as string
						set thisPage to ((((characters ((offset of "?page=" in thisParagraph) + 6) thru -2 in thisParagraph) as string) as integer) + 1) as string
						set finish to false
					else
						if thisParagraph begins with "* " then
							set thisAnnotation to (characters 3 thru -1 in thisParagraph) as string
							set finish to true
						else
							set end of thisAnnotation_Details to thisParagraph
							set finish to true
						end if
					end if
					if finish = true then
						if i > 3 and i < theParagraphs_count then
							set lastParagraph to (item (i - 1) in theParagraphs) as string
							if lastParagraph does not start with "# " then
								set nextParagraph to (item (i + 1) in theParagraphs) as string
								if nextParagraph begins with "* " or nextParagraph begins with "## [Page " or nextParagraph begins with "# " then
									set end of the_record to {annotation_:thisAnnotation, details_:my tid(thisAnnotation_Details, linefeed), sourcepdf_:thisPDF_Name, page_:thisPage, rurl_:thisPageRefURL}
									set thisAnnotation_Details to {}
								end if
							end if
						else if i = theParagraphs_count then
							set end of the_record to {annotation_:thisAnnotation, details_:my tid(thisAnnotation_Details, linefeed), sourcepdf_:thisPDF_Name, page_:thisPage, rurl_:thisPageRefURL}
							set thisAnnotation_Details to {}
						end if
					end if
				end repeat
				
				set thisRecord_Name to my recordName(name of thisRecord, filename of thisRecord)
				if thisRecord_Name contains "/" then set thisRecord_Name to my replaceString(thisRecord_Name, "/", "-")
				set theColumns to {"Name", "SourcePDF", "Annotation", "Details", "Pages", "URL", "Text"}
				set theTSVRecord to create record with {name:thisRecord_Name, type:sheet, columns:theColumns} in theOutputGroup
				set theData_Dummy to {"Delete me", "Source PDF", "Annotation", "Details", "0", "URL", "Text"}
				set theCells to cells of theTSVRecord
				set end of theCells to theData_Dummy
				set cells of theTSVRecord to theCells
				
				repeat with this_record in the_record
					set theAnnotation to annotation_ of this_record
					set theDetails to details_ of this_record
					set theDetails_trimmed to my trimBoth(theDetails)
					set theDetails_replaced to my replaceString(theDetails_trimmed, linefeed, " ---LINEFEED--- ")
					if theDetails_replaced = "" then
						set theText to theAnnotation & " ---LINEFEED--- "
					else
						set theText to theAnnotation & " ---LINEFEED--- " & " ---LINEFEED--- " & theDetails_replaced
					end if
					set theSourcePDF to sourcepdf_ of this_record
					set thePage to page_ of this_record
					set theRefURL to rurl_ of this_record
					set this_record_data to {theAnnotation, theSourcePDF, theAnnotation, theDetails_replaced, thePage, theRefURL, theText}
					set theCells to cells of theTSVRecord
					set end of theCells to this_record_data
					set cells of theTSVRecord to theCells
					set this_record_data to {}
				end repeat
			else
				error "Please select some \"Summarize Highlights\" Markdown records"
			end if
		end repeat
		
		open window for record theOutputGroup
		activate
		
		set the clipboard to ("$Name=$Name.replace('\\\"\\\"','\\\"');" & linefeed & linefeed & "$SourcePDF=$SourcePDF.replace('\\\"\\\"','\\\"');" & ¬
			linefeed & linefeed & "$Annotation=$Annotation.replace('\\\"\\\"','\\\"');" & linefeed & linefeed & "$Details=$Details.replace('\\\"\\\"','\\\"').replace(\" ---LINEFEED--- \",\"\\n\");" & linefeed & linefeed & "$Text=$Text.replace('\\\"\\\"','\\\"').replace(\" ---LINEFEED--- \",\"\\n\");") as string
		
		hide progress indicator
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on tid(theInput, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	if class of theInput = text then
		set theOutput to text items of theInput
	else if class of theInput = list then
		set theOutput to theInput as text
	end if
	set AppleScript's text item delimiters to d
	return theOutput
end tid

on trimStart(str)
	local str, whiteSpace
	try
		set str to str as string
		set whiteSpace to {character id 10, return, space, tab}
		try
			repeat while str's first character is in whiteSpace
				set str to str's text 2 thru -1
			end repeat
			return str
		on error number -1728
			return ""
		end try
	on error eMsg number eNum
		error "Can't trimStart: " & eMsg number eNum
	end try
end trimStart

on trimEnd(str)
	local str, whiteSpace
	try
		set str to str as string
		set whiteSpace to {character id 10, return, space, tab}
		try
			repeat while str's last character is in whiteSpace
				set str to str's text 1 thru -2
			end repeat
			return str
		on error number -1728
			return ""
		end try
	on error eMsg number eNum
		error "Can't trimEnd: " & eMsg number eNum
	end try
end trimEnd

on trimBoth(str)
	local str
	try
		return my trimStart(my trimEnd(str))
	on error eMsg number eNum
		error "Can't trimBoth: " & eMsg number eNum
	end try
end trimBoth

on replaceString(theText, oldString, newString)
	local ASTID, theText, oldString, newString, lst
	set ASTID to AppleScript's text item delimiters
	try
		considering case
			set AppleScript's text item delimiters to oldString
			set lst to every text item of theText
			set AppleScript's text item delimiters to newString
			set theText to lst as string
		end considering
		set AppleScript's text item delimiters to ASTID
		return theText
	on error eMsg number eNum
		set AppleScript's text item delimiters to ASTID
		error "Can't replaceString: " & eMsg number eNum
	end try
end replaceString

on recordName(theName, theFilename)
	set theSuffix to my getSuffix(theFilename)
	if theName ends with theSuffix and theName ≠ theSuffix then set theName to characters 1 thru -((length of theSuffix) + 2) in theName as string
	return theName
end recordName

on getSuffix(thePath)
	set revPath to reverse of characters in thePath as string
	set theSuffix to reverse of characters 1 thru ((offset of "." in revPath) - 1) in revPath as string
end getSuffix

3 Likes

A big big thank you @pete31 ! First thanks for your efforts and second for your time to explain the process clearly and illustrate the steps.

Just tried out a the steps on a 210+ annotations file and it worked flawlessly.

I now have a working process for all my highlighted PDFs in DevonThink. Here an illustration in Tinderbox with a few of the notes marked in colour.

1 Like

Since Tinderbox v8+ has a scripting dictionary, a subsequent version of this might consider just creating the notes directly into Tinderbox and avoid the TSV business. Tinderbox handles TSV import better than CSV, but TSV can still choke Tinderbox from time to time. YMMV.

Nice!

OMG @pete31, this is AWESOME!!! Thank you so much. :slight_smile:

Pete, one question though. Sorry, I know nothing about AppleScript otherwise I’d try the update myself. If I were to want to pass some custom fields from DT3 to Tinderbox, along with everything else, which I do (Citation and Bibliography) how would I do that?

1 Like

Depends on what properties exactly you want to include in the note’s KeyAttributes - and what Tinderbox data type they should have (please see Setting up for Tab-Delimited Import).

For any property that should be additionally included these are the steps:

  • Get the property from thisPDF
  • Include it when adding to AppleScript record the_record
  • Add a name for the attribute in theColumns
  • Add a dummy value for the attribute in theData_Dummy
  • Get it when fetching from AppleScript record the_record
  • Convert it to the desired Tinderbox data type (see link above)
  • Include the converted data in this_record_data
  • Additionally it might be necessary to replace linefeeds and modify stamp 1.

It might not be possible to import every additional property in the desired data type without some little manual setup in Tinderbox (see link above).

If you tell me

  • what properties you want to add
  • what data type they should have in Tinderbox (see link above)

I’ll take a look. In case I encounter difficulties with converting to the desired data type(s) I suggest we move discussion to the Tinderbox forum.

Here is an example. To be specific, I’ve created two custom fields in DT3. I’d love to have them passed to the same fields in Tinderbox.

Try this

Click to see the script
-- Create "Summarize Highlights" TSV for import into Tinderbox - including custom meta data "citation" and "bibliography"

-- In DEVONthink: With one or more selected PDF(s): menu "Tools > Summarize Highlight > as Markdown"
-- Select resulting Markdown record(s)
-- Run script
-- Drag resulting TSV(s) into Finder, e.g. desktop
-- In Finder: Drag TSV(s) into Tinderbox
-- In Tinderbox: Use at least the first stamp (it's copied automatically)

(* Use the first stamp to rebuild double quotes and linefeeds:

$Name=$Name.replace('\"\"','\"');
$SourcePDF=$SourcePDF.replace('\"\"','\"');
$Annotation=$Annotation.replace('\"\"','\"');
$Details=$Details.replace('\"\"','\"').replace(" ---LINEFEED--- ","\n");
$Text=$Text.replace('\"\"','\"').replace(" ---LINEFEED--- ","\n");

Optionally: Use the second stamp to group annotation notes:

$Container=$Container+$SourcePDF;

*)

tell application id "DNtp"
	try
		set theRecords to selected records
		if theRecords = {} then error "Please select some \"Summarize Highlights\" Markdown records"
		set theOutputGroup to display group selector "Choose output group:"
		show progress indicator "Creating TSV... " steps (count theRecords) as string with cancel button
		
		repeat with thisRecord in theRecords
			set theType to (type of thisRecord) as string
			if theType is in {"markdown", "«constant ****mkdn»"} then
				step progress indicator "... " & (name of thisRecord) as string
				set theText to plain text of thisRecord
				set theParagraphs to paragraphs of theText
				set theParagraphs_count to (count theParagraphs)
				set the_record to {}
				set thisAnnotation_Details to {}
				
				repeat with i from 1 to theParagraphs_count
					set thisParagraph to (item i in theParagraphs) as string
					set thisParagraph to my trimEnd(thisParagraph)
					if thisParagraph begins with "# " then
						set thisPDF_UUID to characters ((offset of "](x-devonthink-item://" in thisParagraph) + 22) thru -2 in thisParagraph as string
						set thisPDF to (get record with uuid thisPDF_UUID)
						set thisPDF_Name to my recordName(name of thisPDF, filename of thisPDF)
						if thisPDF_Name contains "/" then set thisPDF_Name to my replaceString(thisPDF_Name, "/", "-")
						
						set thisPDF_custommetadata_citation to (get custom meta data for "citation" from thisPDF) as string
						if thisPDF_custommetadata_citation = "missing value" then set thisPDF_custommetadata_citation to ""
						set thisPDF_custommetadata_bibliography to (get custom meta data for "bibliography" from thisPDF) as string
						if thisPDF_custommetadata_bibliography = "missing value" then set thisPDF_custommetadata_bibliography to ""
						
						set finish to false
					else if thisParagraph begins with "## [Page " then
						set thisPageRefURL to (characters ((offset of "](" in thisParagraph) + 2) thru -2 in thisParagraph) as string
						set thisPage to ((((characters ((offset of "?page=" in thisParagraph) + 6) thru -2 in thisParagraph) as string) as integer) + 1) as string
						set finish to false
					else
						if thisParagraph begins with "* " then
							set thisAnnotation to (characters 3 thru -1 in thisParagraph) as string
							set finish to true
						else
							set end of thisAnnotation_Details to thisParagraph
							set finish to true
						end if
					end if
					if finish = true then
						if i > 3 and i < theParagraphs_count then
							set lastParagraph to (item (i - 1) in theParagraphs) as string
							if lastParagraph does not start with "# " then
								set nextParagraph to (item (i + 1) in theParagraphs) as string
								if nextParagraph begins with "* " or nextParagraph begins with "## [Page " or nextParagraph begins with "# " then
									set end of the_record to {annotation_:thisAnnotation, details_:my tid(thisAnnotation_Details, linefeed), sourcepdf_:thisPDF_Name, page_:thisPage, rurl_:thisPageRefURL, custommetadata_citation_:thisPDF_custommetadata_citation, custommetadata_bibliography_:thisPDF_custommetadata_bibliography}
									set thisAnnotation_Details to {}
								end if
							end if
						else if i = theParagraphs_count then
							set end of the_record to {annotation_:thisAnnotation, details_:my tid(thisAnnotation_Details, linefeed), sourcepdf_:thisPDF_Name, page_:thisPage, rurl_:thisPageRefURL, custommetadata_citation_:thisPDF_custommetadata_citation, custommetadata_bibliography_:thisPDF_custommetadata_bibliography}
							set thisAnnotation_Details to {}
						end if
					end if
				end repeat
				
				set thisRecord_Name to my recordName(name of thisRecord, filename of thisRecord)
				if thisRecord_Name contains "/" then set thisRecord_Name to my replaceString(thisRecord_Name, "/", "-")
				set theColumns to {"Name", "SourcePDF", "Citation", "Bibliography", "Annotation", "Details", "Pages", "URL", "Text"}
				set theTSVRecord to create record with {name:thisRecord_Name, type:sheet, columns:theColumns} in theOutputGroup
				set theData_Dummy to {"Delete me", "Source PDF", "Citation", "Bibliography", "Annotation", "Details", "0", "URL", "Text"}
				set theCells to cells of theTSVRecord
				set end of theCells to theData_Dummy
				set cells of theTSVRecord to theCells
				
				repeat with this_record in the_record
					set theAnnotation to annotation_ of this_record
					set theDetails to details_ of this_record
					set theDetails_trimmed to my trimBoth(theDetails)
					set theDetails_replaced to my replaceString(theDetails_trimmed, linefeed, " ---LINEFEED--- ")
					if theDetails_replaced = "" then
						set theText to theAnnotation & " ---LINEFEED--- "
					else
						set theText to theAnnotation & " ---LINEFEED--- " & " ---LINEFEED--- " & theDetails_replaced
					end if
					set theSourcePDF to sourcepdf_ of this_record
					set thePage to page_ of this_record
					set theRefURL to rurl_ of this_record
					
					set theCitation to custommetadata_citation_ of this_record
					set theBibliography to custommetadata_bibliography_ of this_record
					
					set this_record_data to {theAnnotation, theSourcePDF, theCitation, theBibliography, theAnnotation, theDetails_replaced, thePage, theRefURL, theText}
					set theCells to cells of theTSVRecord
					set end of theCells to this_record_data
					set cells of theTSVRecord to theCells
					set this_record_data to {}
				end repeat
			else
				error "Please select some \"Summarize Highlights\" Markdown records"
			end if
		end repeat
		
		open window for record theOutputGroup
		activate
		
		set the clipboard to ("$Name=$Name.replace('\\\"\\\"','\\\"');" & linefeed & linefeed & "$SourcePDF=$SourcePDF.replace('\\\"\\\"','\\\"');" & ¬
			linefeed & linefeed & "$Annotation=$Annotation.replace('\\\"\\\"','\\\"');" & linefeed & linefeed & "$Details=$Details.replace('\\\"\\\"','\\\"').replace(\" ---LINEFEED--- \",\"\\n\");" & linefeed & linefeed & "$Text=$Text.replace('\\\"\\\"','\\\"').replace(\" ---LINEFEED--- \",\"\\n\");") as string
		
		hide progress indicator
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on tid(theInput, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	if class of theInput = text then
		set theOutput to text items of theInput
	else if class of theInput = list then
		set theOutput to theInput as text
	end if
	set AppleScript's text item delimiters to d
	return theOutput
end tid

on trimStart(str)
	local str, whiteSpace
	try
		set str to str as string
		set whiteSpace to {character id 10, return, space, tab}
		try
			repeat while str's first character is in whiteSpace
				set str to str's text 2 thru -1
			end repeat
			return str
		on error number -1728
			return ""
		end try
	on error eMsg number eNum
		error "Can't trimStart: " & eMsg number eNum
	end try
end trimStart

on trimEnd(str)
	local str, whiteSpace
	try
		set str to str as string
		set whiteSpace to {character id 10, return, space, tab}
		try
			repeat while str's last character is in whiteSpace
				set str to str's text 1 thru -2
			end repeat
			return str
		on error number -1728
			return ""
		end try
	on error eMsg number eNum
		error "Can't trimEnd: " & eMsg number eNum
	end try
end trimEnd

on trimBoth(str)
	local str
	try
		return my trimStart(my trimEnd(str))
	on error eMsg number eNum
		error "Can't trimBoth: " & eMsg number eNum
	end try
end trimBoth

on replaceString(theText, oldString, newString)
	local ASTID, theText, oldString, newString, lst
	set ASTID to AppleScript's text item delimiters
	try
		considering case
			set AppleScript's text item delimiters to oldString
			set lst to every text item of theText
			set AppleScript's text item delimiters to newString
			set theText to lst as string
		end considering
		set AppleScript's text item delimiters to ASTID
		return theText
	on error eMsg number eNum
		set AppleScript's text item delimiters to ASTID
		error "Can't replaceString: " & eMsg number eNum
	end try
end replaceString

on recordName(theName, theFilename)
	set theSuffix to my getSuffix(theFilename)
	if theName ends with theSuffix and theName ≠ theSuffix then set theName to characters 1 thru -((length of theSuffix) + 2) in theName as string
	return theName
end recordName

on getSuffix(thePath)
	set revPath to reverse of characters in thePath as string
	set theSuffix to reverse of characters 1 thru ((offset of "." in revPath) - 1) in revPath as string
end getSuffix

Ok, @pete31 you are amazing! Thank you. I learned from your example and modify the script to add one more custom variable, “PublicationYear”. It worked perfectly.

Thank you again.

-- Create "Summarize Highlights" TSV for import into Tinderbox - including custom meta data "citation", "bibliography", and "Publication Year".

-- In DEVONthink: With one or more selected PDF(s): menu "Tools > Summarize Highlight > as Markdown"
-- Select resulting Markdown record(s)
-- Run script
-- Drag resulting TSV(s) into Finder, e.g. desktop
-- In Finder: Drag TSV(s) into Tinderbox
-- In Tinderbox: Use at least the first stamp (it's copied automatically)

(* Use the first stamp to rebuild double quotes and linefeeds:

$Name=$Name.replace('\"\"','\"');
$SourcePDF=$SourcePDF.replace('\"\"','\"');
$Annotation=$Annotation.replace('\"\"','\"');
$Details=$Details.replace('\"\"','\"').replace(" ---LINEFEED--- ","\n");
$Text=$Text.replace('\"\"','\"').replace(" ---LINEFEED--- ","\n");

Optionally: Use the second stamp to group annotation notes:

$Container=$Container+$SourcePDF;

*)

tell application id "DNtp"
	try
		set theRecords to selected records
		if theRecords = {} then error "Please select some \"Summarize Highlights\" Markdown records"
		set theOutputGroup to display group selector "Choose output group:"
		show progress indicator "Creating TSV... " steps (count theRecords) as string with cancel button
		
		repeat with thisRecord in theRecords
			set theType to (type of thisRecord) as string
			if theType is in {"markdown", "«constant ****mkdn»"} then
				step progress indicator "... " & (name of thisRecord) as string
				set theText to plain text of thisRecord
				set theParagraphs to paragraphs of theText
				set theParagraphs_count to (count theParagraphs)
				set the_record to {}
				set thisAnnotation_Details to {}
				
				repeat with i from 1 to theParagraphs_count
					set thisParagraph to (item i in theParagraphs) as string
					set thisParagraph to my trimEnd(thisParagraph)
					if thisParagraph begins with "# " then
						set thisPDF_UUID to characters ((offset of "](x-devonthink-item://" in thisParagraph) + 22) thru -2 in thisParagraph as string
						set thisPDF to (get record with uuid thisPDF_UUID)
						set thisPDF_Name to my recordName(name of thisPDF, filename of thisPDF)
						if thisPDF_Name contains "/" then set thisPDF_Name to my replaceString(thisPDF_Name, "/", "-")
						
						set thisPDF_custommetadata_citation to (get custom meta data for "citation" from thisPDF) as string
						if thisPDF_custommetadata_citation = "missing value" then set thisPDF_custommetadata_citation to ""
						set thisPDF_custommetadata_bibliography to (get custom meta data for "bibliography" from thisPDF) as string
						if thisPDF_custommetadata_bibliography = "missing value" then set thisPDF_custommetadata_bibliography to ""
						set thisPDF_custommetadata_publicationyear to (get custom meta data for "publicationyear" from thisPDF) as string
						if thisPDF_custommetadata_publicationyear = "missing value" then set thisPDF_custommetadata_publicationyear to ""
						
						set finish to false
					else if thisParagraph begins with "## [Page " then
						set thisPageRefURL to (characters ((offset of "](" in thisParagraph) + 2) thru -2 in thisParagraph) as string
						set thisPage to ((((characters ((offset of "?page=" in thisParagraph) + 6) thru -2 in thisParagraph) as string) as integer) + 1) as string
						set finish to false
					else
						if thisParagraph begins with "* " then
							set thisAnnotation to (characters 3 thru -1 in thisParagraph) as string
							set finish to true
						else
							set end of thisAnnotation_Details to thisParagraph
							set finish to true
						end if
					end if
					if finish = true then
						if i > 3 and i < theParagraphs_count then
							set lastParagraph to (item (i - 1) in theParagraphs) as string
							if lastParagraph does not start with "# " then
								set nextParagraph to (item (i + 1) in theParagraphs) as string
								if nextParagraph begins with "* " or nextParagraph begins with "## [Page " or nextParagraph begins with "# " then
									set end of the_record to {annotation_:thisAnnotation, details_:my tid(thisAnnotation_Details, linefeed), sourcepdf_:thisPDF_Name, page_:thisPage, rurl_:thisPageRefURL, custommetadata_citation_:thisPDF_custommetadata_citation, custommetadata_bibliography_:thisPDF_custommetadata_bibliography, custommetadata_publicationyear_:thisPDF_custommetadata_publicationyear}
									set thisAnnotation_Details to {}
								end if
							end if
						else if i = theParagraphs_count then
							set end of the_record to {annotation_:thisAnnotation, details_:my tid(thisAnnotation_Details, linefeed), sourcepdf_:thisPDF_Name, page_:thisPage, rurl_:thisPageRefURL, custommetadata_citation_:thisPDF_custommetadata_citation, custommetadata_bibliography_:thisPDF_custommetadata_bibliography, custommetadata_publicationyear_:thisPDF_custommetadata_publicationyear}
							set thisAnnotation_Details to {}
						end if
					end if
				end repeat
				
				set thisRecord_Name to my recordName(name of thisRecord, filename of thisRecord)
				if thisRecord_Name contains "/" then set thisRecord_Name to my replaceString(thisRecord_Name, "/", "-")
				set theColumns to {"Name", "SourcePDF", "Citation", "Bibliography", "PublicationYear", "Annotation", "Details", "Pages", "URL", "Text"}
				set theTSVRecord to create record with {name:thisRecord_Name, type:sheet, columns:theColumns} in theOutputGroup
				set theData_Dummy to {"Delete me", "Source PDF", "Citation", "Bibliography", "PublicationYear", "Annotation", "Details", "0", "URL", "Text"}
				set theCells to cells of theTSVRecord
				set end of theCells to theData_Dummy
				set cells of theTSVRecord to theCells
				
				repeat with this_record in the_record
					set theAnnotation to annotation_ of this_record
					set theDetails to details_ of this_record
					set theDetails_trimmed to my trimBoth(theDetails)
					set theDetails_replaced to my replaceString(theDetails_trimmed, linefeed, " ---LINEFEED--- ")
					if theDetails_replaced = "" then
						set theText to theAnnotation & " ---LINEFEED--- "
					else
						set theText to theAnnotation & " ---LINEFEED--- " & " ---LINEFEED--- " & theDetails_replaced
					end if
					set theSourcePDF to sourcepdf_ of this_record
					set thePage to page_ of this_record
					set theRefURL to rurl_ of this_record
					
					set theCitation to custommetadata_citation_ of this_record
					set theBibliography to custommetadata_bibliography_ of this_record
					set thePublicationYear to custommetadata_publicationyear_ of this_record
					
					set this_record_data to {theAnnotation, theSourcePDF, theCitation, theBibliography, thePublicationYear, theAnnotation, theDetails_replaced, thePage, theRefURL, theText}
					set theCells to cells of theTSVRecord
					set end of theCells to this_record_data
					set cells of theTSVRecord to theCells
					set this_record_data to {}
				end repeat
			else
				error "Please select some \"Summarize Highlights\" Markdown records"
			end if
		end repeat
		
		open window for record theOutputGroup
		activate
		
		set the clipboard to ("$Name=$Name.replace('\\\"\\\"','\\\"');" & linefeed & linefeed & "$SourcePDF=$SourcePDF.replace('\\\"\\\"','\\\"');" & ¬
			linefeed & linefeed & "$Annotation=$Annotation.replace('\\\"\\\"','\\\"');" & linefeed & linefeed & "$Details=$Details.replace('\\\"\\\"','\\\"').replace(\" ---LINEFEED--- \",\"\\n\");" & linefeed & linefeed & "$Text=$Text.replace('\\\"\\\"','\\\"').replace(\" ---LINEFEED--- \",\"\\n\");") as string
		
		hide progress indicator
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on tid(theInput, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	if class of theInput = text then
		set theOutput to text items of theInput
	else if class of theInput = list then
		set theOutput to theInput as text
	end if
	set AppleScript's text item delimiters to d
	return theOutput
end tid

on trimStart(str)
	local str, whiteSpace
	try
		set str to str as string
		set whiteSpace to {character id 10, return, space, tab}
		try
			repeat while str's first character is in whiteSpace
				set str to str's text 2 thru -1
			end repeat
			return str
		on error number -1728
			return ""
		end try
	on error eMsg number eNum
		error "Can't trimStart: " & eMsg number eNum
	end try
end trimStart

on trimEnd(str)
	local str, whiteSpace
	try
		set str to str as string
		set whiteSpace to {character id 10, return, space, tab}
		try
			repeat while str's last character is in whiteSpace
				set str to str's text 1 thru -2
			end repeat
			return str
		on error number -1728
			return ""
		end try
	on error eMsg number eNum
		error "Can't trimEnd: " & eMsg number eNum
	end try
end trimEnd

on trimBoth(str)
	local str
	try
		return my trimStart(my trimEnd(str))
	on error eMsg number eNum
		error "Can't trimBoth: " & eMsg number eNum
	end try
end trimBoth

on replaceString(theText, oldString, newString)
	local ASTID, theText, oldString, newString, lst
	set ASTID to AppleScript's text item delimiters
	try
		considering case
			set AppleScript's text item delimiters to oldString
			set lst to every text item of theText
			set AppleScript's text item delimiters to newString
			set theText to lst as string
		end considering
		set AppleScript's text item delimiters to ASTID
		return theText
	on error eMsg number eNum
		set AppleScript's text item delimiters to ASTID
		error "Can't replaceString: " & eMsg number eNum
	end try
end replaceString

on recordName(theName, theFilename)
	set theSuffix to my getSuffix(theFilename)
	if theName ends with theSuffix and theName ≠ theSuffix then set theName to characters 1 thru -((length of theSuffix) + 2) in theName as string
	return theName
end recordName

on getSuffix(thePath)
	set revPath to reverse of characters in thePath as string
	set theSuffix to reverse of characters 1 thru ((offset of "." in revPath) - 1) in revPath as string
end getSuffix
1 Like

Hey! Is it possible to import annotations faster after last update of DT3? It introduced “Summarize Highlights”'s Sheet output, but moving annotations file outside of DT and then to TBX shows note with some strange attributes and no $text…

Hi Pete,

This looks brilliant. Thank you so much for sharing. will definitely have to give it a try. Does the script create single notes for each highlighted section? If so, is there a way to format the Tinderbox Note Box to have the annotation color as a property?

Stay safe and thanks again!

Johannes

No, the script uses DEVONthink’s “Summarize Highlights” Markdown output which doesn’t include info about the annotation color.

It should be possible to get the annotation color from DEVONthink’s “Summarize Highlights” RTF output but that would make it necessary to write a complete new script - and I really don’t like RTF scripting.

cheers for taking the time to answer my post. That sounds like too much work without much joy. (I can’t even attempt it as I have literally no clue about scripting of any form).

cheers and all the best,

j.

I was able to follow the instructions create the script and the stamp and get them into tinderbox but except for my notes on all annotations I highlighted or underlined I get a {== or a {++ at the beginning and end of all of my annotations. How can I keep that from happening or is there some kind of stamp that I can apply that removes this?

Welcome @runner57

That is CriticMarkup syntax for highlighted and underlined content. @pete31 would have to answer on the specifics of his script.

At the time the script was written DEVONthink didn’t add CriticMarkup to the „Summarize Highlight“ output.

I‘m not sure what’s the benefit of using CriticMarkup here as CriticMarkup only supports one highlighting color, but PDF annotation highlights of course support any color. So what we currently get is a „Summarize Highlight“ Markdown output that shows all highlights in yellow, not matter if the actually used highlight color was red, blue or pink.


@runner57 I‘ll see whether it’s easy to adopt the script to the new circumstances.

As a workaround you could open the resulting record in e.g. BBEdit and do a search and replace for the CriticMarkup syntax. (Should also be possible to replace in DEVONthink)

can I maybe bump this thread to see if any solution has bern found?