forked from RobTrew/tree-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSkimToDevn-023.applescript
505 lines (440 loc) · 19.6 KB
/
SkimToDevn-023.applescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
property pScriptTitle : "Skim Notes to Devonthink"property pVer : ".023"property pblnAvoidDuplication : true -- If true, will not create duplicate records (on a second run) in the target groupproperty pblnGetKeywordsAndTags : trueproperty pblnQuickTagsOnly : false -- If true, will only export user-assigned keywords-- EDIT THE FOLLOWING VALUE TO false IF YOU WISH TO SUPPRESS INDEXING AND LINKING OF THE PDFproperty pblnIndexPDF : true-- Copyright © 2011, Robin Trew - Houthakker-- All rights reserved.-- -- Redistribution and use in source and binary forms, with or without modification, -- are permitted provided that the following conditions are met:-- -- - Redistributions of source code must retain the above copyright notice, -- this list of conditions and the following disclaimer.-- - Redistributions in binary form must reproduce the above copyright notice, -- this list of conditions and the following disclaimer in the documentation -- and/or other materials provided with the distribution.-- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -- IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-- RECENT CHANGE LOG-- ver .001 First rough draft-- ver .002 Minor corrections to growl message-- ver .003 pShowYPosn and pShowXPosn switches (below) add sortable note coordinates to page number-- ver .004 added minor details at foot of note: modification date/time, note type, note position, icon type, user (should be easy to comment out or adjust)-- also added new CSS style for these details: .detail {color:#888888; margin-left: 30px; font-family: "lucida grande", "sans-serif"; font-size:8px;}-- ver .005 The text of strikethrough notes tagged as <struck>, and given, in the default CSS, the format: {text-decoration:line-through}-- ver .006 Corrects the order of the sortable vertical position numbers (it turns out the that 0 is at bottom left)-- ver .007 Textless notes (e.g. arrows without attached text) are no longer exported-- ver .008 Three styles added to CSS to allow for special styling of Skim 'srike out notes', 'highlight notes', and 'underline notes'-- the CSS definitions of struck | highlit | underscored (below) can be adjusted, -- or simply reduced to {} to avoid application of special style-- ver .009 Corrected vertical position numbers in source details (to assume y orgin at bottom)-- ver .010 Will not create a new group if the PDF open in Skim is the only PDF in the group.-- ver .018 Changes the name of the css that it written/read (for compatibility with other scripts)-- (If you have customized a css file for this script you will need to rename it or copy it to DevnNote.css)-- ver 0.22 Temporarily suppressed modification date recording, as the latest Skim version has difficulty with this------------------------------------------------------------------------------------------------------------ FUNCTION-- Copies notes from Skim to the current folder of DEVONthink 2-- For each document open in Skim, a correspondingly named folder is created -- within the currently selected DevonThink folder-- For each note, an RTF record, with a URL link back to the PDF page is created in the folder-- USAGE-- Select a target DevonThink group,-- Open one or more PDFs in Skim,-- Run this script.----------------------------------------------------------------------------------------------------------property pstrDefaultCSS : " .header {color:#888888;} .quote {color:#333366; margin-left: 30px; margin-right: 30px; line-height: 140%;} .comment {color:#222222; margin-left: 30px; line-height: 140%;} .wptag {color:#888888;}
.detail {color:#888888; margin-left: 30px; font-family: \"lucida grande\", \"sans-serif\"; font-size:8px;}
struck {text-decoration:line-through}
highlit {background-color:#FEFC97}
underscored {text-decoration:underline} p {font-family: monospace; font-size:12px} i {font-family: monospace; font-style:italic;} b {font-family: monospace; font-weight:bold;} u {font-family: monospace} "property pstrActiveCSS : "" -- will be defined at run-time either by pstrDefaultCSS (above),-- or by the contents of any external pCSSfile (see below).-- NOTE: CUSTOMIZING NOTE STYLE WITH EXTERNAL CSS FILE-- (TO AVOID RE-EDITING AFTER SCRIPT UPDATES)-- An optional customized css file can be placed in the same folder as this script, -- to retain customized formatting if a later version of this script is downloaded.-- The contents of this file (if its exists) will be used as an alternative to pstrDefaultCSS above,-- and should define the same set of styles. -- If such a file is desired, it should have the name specified in the following property (pCSSFile):property pCSSFile : "DevnNote.css"property pblnPageFirst : true -- Edit this to give records names which start with a sortable page number like "(@055)" property pShowYPosn : true -- Edit to follow page number with sortable vertical coordinates of note on page (sort top to bottom)property pShowXPosn : false -- ditto for horizontal coordinates (sort by left to right posn)on run -- CHECK THAT DEVONTHINK IS RUNNING if application id "DNtp" is not running then tell application id "sevs" activate display dialog "DEVONthink Pro not running ..." & return & return & ¬ "Start DEVONthink Pro, and run the script again." buttons {"OK"} with title pScriptTitle end tell return end if -- CHECK THAT SKIM IS RUNNING if not IsRunning("SKim") then tell application id "sevs" activate display dialog "Open a PDF in Skim, and run the script again." buttons {"OK"} with title pScriptTitle end tell return else -- AND THAT AT LEAST ONE PDF IS OPEN tell application id "SKim" try set lstSkimDocs to documents on error tell application id "sevs" activate display dialog "No documents open in Skim ..." & return & return & ¬ "Open a PDF in Skim, and run the script again." buttons {"OK"} with title pScriptTitle end tell return end try end tell end if set {oRootGroup, oRootWin} to my GetGroupWin() -- FOR EACH PDF OPEN IN SKIM, CREATE A GROUP IN DT AND EXPORT THE NOTES TO THE GROUP GetSkimNotes(lstSkimDocs, oRootGroup)end runon IsRunning(strCode) -- DNtp / SKim tell application id "com.apple.systemevents" (count of (processes where creator type = strCode)) > 0 end tellend IsRunningon GetSkimNotes(lstPDF, oRootGroup) -- QUIT IF NO PDFS SELECTED set lngPDF to length of lstPDF if lngPDF < 1 then --tell application id "com.devon-technologies.thinkpro2" to hide progress indicator tell application id "sevs" activate display dialog "No PDFs open in Skim" buttons {"OK"} with title pScriptTitle & " Ver " & pVer end tell return else -- Assuming that we are dealing with selected DT records, for the moment -- If records are to be formatted, see if there is a .css file (named as in pCSSFile above) -- in the same folder as this script. -- If not, fall back to the default CSS style set pstrActiveCSS to my GetCSS() if (length of pstrActiveCSS) = 0 then set pstrActiveCSS to pstrDefaultCSS tell application id "SKim" repeat with i from 1 to lngPDF tell (document i) set lngPages to count of pages set strPDFPath to POSIX path of (its file as string) set strPDFName to its name -- USE THE FIRST LINE OF TEXT AS THE DEFAULT NAME OF THE DOCUMENT set strDocName to "" set refParas to (a reference to (paragraphs of its text)) repeat with oPara in refParas set strPara to oPara as string if length of strPara > 1 then set strDocName to text 1 thru -2 of strPara exit repeat end if end repeat -- WE WANT A FOLDER WHICH IS EITHER: -- 1. EMPTY -- 2.OR CONTAINS ONLY ONE PDF RECORD, WHICH CONTAINS OR INDEXES THE CURRENT PDF -- FIND OR CREATE A DT FOLDER FOR THE NOTES OF THIS DOCUMENT tell application id "DNtp" set oLocn to oRootGroup if (count of children of oRootGroup) > 0 then set lstGroupPDF to (children of oRootGroup where type = PDF document) set lngPDF to count of lstGroupPDF if lngPDF > 0 then if (lngPDF > 1) or ((path of first item of lstGroupPDF) ≠ strPDFPath) then ¬ set oLocn to (create location (location of oRootGroup & "/" & name of oRootGroup & "/" & strDocName) in database of oRootGroup) end if end if if pblnIndexPDF then -- FIND OR CREATE A REFERENCE TO THIS DOCUMENT IN THAT FOLDER set lstDuplic to (children of oLocn where path is strPDFPath) if length of lstDuplic < 1 then set oPDFRec to indicate strPDFPath to oLocn else set oPDFRec to first item of lstDuplic end if set strUUID to reference URL of oPDFRec end if end tell tell (a reference to (notes)) set lngNotes to count if lngNotes < 1 then return -- GET WHOLE PROPERTY LISTS TO ECONOMIZE ON APPLE EVENTS set refPage to (a reference to its page) set {lstNoteBounds, lstComment, lstIcon, lstpage, lstPageBounds, lstRTF, lstText, lstType, lstUser} to ¬ {bounds, extended text, icon, index of refPage, bounds of refPage, its RTF, its text, its type, user name} end tell -- IF WE ARE GOING TO ADD SORTABLE NOTE COORDINATES TO THE PAGE NUMBER, -- FIND THE MAXIMA SO THAT WE CAN LEFT-PAD THE DIGIT STRINGS WITH ZEROS, WHERE NEEDED, -- TO ENSURE PROPER SORTING if (pShowYPosn or pShowXPosn) then set {lngYMax, lngXMax} to {0, 0} repeat with i from 1 to lngNotes set {lngX, lngY} to items 1 thru 2 of (item i of lstNoteBounds) if lngX > lngXMax then set lngXMax to lngX if lngY > lngYMax then set lngYMax to lngY end repeat set lngYdigits to length of (lngYMax as string) set lngXdigits to length of (lngXMax as string) end if -- PROCESS NOTES ONE BY ONE set lngDigits to length of (lngPages as string) repeat with i from 1 to lngNotes -- CHECK THAT THERE IS AT LEAST A QUOTATION OR A COMMENT set eType to item i of lstType if eType = line then -- Line notes fail to return any data to their text method, so we read the rtf set refRTF to (a reference to item i of lstRTF) tell application id "com.apple.finder" set the clipboard to (refRTF as «class RTF ») set strQuotn to do shell script "pbpaste -Prefer rtf | textutil -format rtf -convert txt -stdin -stdout" end tell else set strQuotn to item i of lstText end if set strComment to item i of lstComment if strComment is missing value then set strComment to "" -- ONLY EXPORT A NOTE IF THERE IS SOME TEXT if (length of strQuotn > 0) or (length of strComment > 0) then set strType to eType as string -- GET THE OTHER INTERESTING PROPERTIES set lstXYWH to item i of lstNoteBounds if strComment is missing value then set strComment to "" set strIcon to (item i of lstIcon) as string --set dteModn to item i of lstModn set lngPage to (item i of lstpage) set lngPageHeight to (item 2 of (item i of lstPageBounds)) set varUser to (item i of lstUser) if varUser = missing value then set varUser to "" set strRecName to my GetFirstLine(strQuotn) -- BUILD A DT NOTE IN HTML WITH FIELDS MATCHING THE TYPE OF THE DT NOTE if eType = anchored note then else if eType = highlight note then set strQuotn to "<highlit>" & strQuotn & "<highlit/>" else if eType = strike out note then set strQuotn to "<struck>" & strQuotn & "<struck/>" else if eType = underline note then set strQuotn to "<underscored>" & strQuotn & "</underscored>" end if end if -- ASSEMBLE THE HTML set lngTopY to missing value if pblnPageFirst then set strPrefix to "(@" & my PadNum(lngPage, lngDigits) if pShowYPosn then set lngTopY to (lngPageHeight - (item 2 of lstXYWH)) set strPrefix to (strPrefix & tab & my PadNum(lngTopY, lngYdigits) & "y") end if if pShowXPosn then set strPrefix to (strPrefix & tab & my PadNum(item 1 of lstXYWH, lngXdigits) & "x") set strPrefix to strPrefix & ") " set strRecName to strPrefix & tab & strRecName end if if pblnIndexPDF then set strURL to strUUID & "?page=" & (lngPage - 1) as string set strPDFLink to ("<a href=\"" & strURL & "\">" & strPDFName & " Page " & lngPage as string) & "</a>" else set strURL to "" set strPDFLink to ("<a href=\"" & strPDFPath & "\">" & strPDFName & " Page " & lngPage as string) & "</a>" end if set strText to "<p class=\"header\">Quotation:" & "<p class=\"quote\">" & strQuotn & "<p class=\"header\">" & ¬ "Comment:" & "<p class=\"comment\">" & strComment & ¬ "<p class=\"wptag\">Source:<p class=\"quote\">" & strPDFLink & "<p class=\"detail\">" -- ADD MINOR NOTE DETAILS (comment out and re-order as appropriate) -- set strText to strText & (short date string of dteModn) & tab -- set strText to strText & (time string of dteModn) & "<br>" set lngTopY to (lngPageHeight - (item 2 of lstXYWH)) set strText to strText & strType & tab & "(" & (item 1 of lstXYWH) & "x " & lngTopY & "y)" & "<br>" set strText to strText & strIcon & "<br>" if varUser ≠ "" then set strText to strText & varUser & "<br>" set strHTML to "
<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">
<html>
<head>
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">
<meta http-equiv=\"Content-Style-Type\" content=\"text/css\">
<title></title>
<style type=\"text/css\">
" & pstrActiveCSS & "
</style>
</head>
<body>" & strText & "</body>" -- CREATE THE FORMATTED RTF RECORD tell application id "DNtp" -- Use DT's own HTML to RTF conversion set oHTML to create record with {type:html, source:strHTML, URL:strURL} in oLocn set oNewRec to convert record oHTML to rich delete record oHTML set name of oNewRec to strRecName if pblnAvoidDuplication then -- DISCARD NEW RECORD IF IT DUPLICATES ANOTHER IN THIS GROUP set lstDuplics to duplicates of oNewRec if lstDuplics ≠ {} then set strLocn to location of oNewRec repeat with oDuplic in lstDuplics if location of oDuplic = strLocn then delete record oNewRec exit repeat end if end repeat end if end if end tell end if end repeat end tell end repeat end tell end if -- NOTIFY COMPLETION BY GROWL Growl(oLocn, lngPDF) -- DISPLAY THE TARGET GROUP (OR DATABASE OR INBOX) IN DT2 DT2ForeGround()end GetSkimNoteson GetFirstLine(strQuotn) repeat with oPara in paragraphs of strQuotn if length of oPara > 1 then return oPara as string end repeat return ""end GetFirstLine------------------------------------------------------------------------------------------------------------------------on Growl(oGroup, lngRefs) -- If Growl is running, report the notes sent tell application id "com.devon-technologies.thinkpro2" set {strFolder, strDb} to {name, name of database} of oGroup set strTarget to "current folder " & strFolder & return & return & "of DEVONthink database \"" & strDb & "\"" end tell if lngRefs > 0 then if lngRefs = 1 then set strRefInflection to " PDF" else set strRefInflection to " PDFs" end if tell application "System Events" set blnGrowlRunning to (count of (every process whose name is "GrowlHelperApp")) > 0 if blnGrowlRunning then -- set strReport to text 1 thru ((length of strReport) - 2) of strReport set strReport to "Exported notes for " & (lngRefs as string) & strRefInflection & " to " & strTarget --& return & return & strReport tell application "Growl" register as application "houthakker scripts" all notifications {"Notes handled"} default notifications {"Notes handled"} icon of application "Sente" notify with name "Notes handled" title "Notes processed" application name "houthakker scripts" description strReport end tell end if end tell end ifend Growlon FrontAppName() tell application id "com.apple.systemevents" set lstApps to name of (application processes where frontmost = true) if lstApps = {} then return "" first item of lstApps end tellend FrontAppNameon DT2ForeGround() tell application id "com.devon-technologies.thinkpro2" hide progress indicator activate end tell tell application id "com.apple.finder" activate front window of application id "com.devon-technologies.thinkpro2" end tellend DT2ForeGroundon GetGroupWin() tell application "DEVONthink Pro" -- CURRENT GROUP, IF THERE IS ONE set oGroup to missing value with timeout of 1 second try set oGroup to current group end try end timeout -- ELSE CURRENT DATABASE, IF THERE IS ONE try oGroup on error set oGroup to (root of database id 1) set oWin to open window for record oGroup return {oGroup, oWin} end try if oGroup is missing value then set oGroup to (root of database id 1) set oWin to open window for record oGroup return {oGroup, oWin} end if -- ENSURE THAT A WINDOW IS OPEN FOR THIS GROUP set {oDb, strID} to {database, id} of oGroup set lstWins to viewer windows where id of its root is strID and name of its root is name of oDb if length of lstWins < 1 then set oWin to open window for record oGroup else set oWin to first item of lstWins end if {oGroup, oWin} end tellend GetGroupWinon GetCSS() -- Try to get the CSS file from the same folder as the script. If not there, return empty string set strcssPath to my GetCSSPath(my pCSSFile) set strCSS to "" if strcssPath is not "" then try set strCSS to my readFile(strcssPath) end try end if strCSSend GetCSSon GetCSSPath(strcssFile) set strFolder to ScriptFolder() as string set strcssPath to POSIX path of (strFolder & strcssFile) tell application "Finder" if not (exists (strcssPath as POSIX file)) then return "" end tell strcssPathend GetCSSPathon ScriptFolder() set strPath to (path to me) as string set strDelim to text item delimiters set text item delimiters to ":" set lstParts to text items of strPath set lngLast to (length of lstParts) - 1 set strFolderPath to (items 1 thru lngLast of lstParts) as string set text item delimiters to strDelim strFolderPath as aliasend ScriptFolderon readFile(unixPath) set foo to (open for access (POSIX file unixPath)) set txt to (read foo for (get eof foo)) close access foo return txtend readFileon PadNum(lngNum, lngDigits) set strNum to lngNum as string set lngGap to (lngDigits - (length of strNum)) repeat while lngGap > 0 set strNum to "0" & strNum set lngGap to lngGap - 1 end repeat strNumend PadNum