Speakable item links

I would like to link from a Niniox Database to documents in DT3. I know about x-devonthink-item: but they are cryptic and cannot be calculated from within the database. I’m looking for something like this:

x-devonthink-item://database/group/subgroup/document

the “cryptic” part is the UUID, afaik. If Ninox can run AppleScript or JavaScript, you could try to get the UUID for a certain /database/group/…/document path from DT.

Update Ninox apparently has no AppleScript support (or for any scripting language). So no luck there.
If it were able to run an external command like osascript, you might still get lucky.

Thanks for your fast replay (as always). Yes, Ninox doesn’t support AppleScript and can’t execute shell scripts.

But you brought me to the idea to write a wrapper with its own url-scheme. I already use such a thing to reveal files in Finder from Ninox.

1 Like

Intriguing. Care to elaborate?

Currently the script looks like this, it’s not testet very well:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

global theScheme, thePath, theURL, theParent, theName, theDatabase, theTab, theRecord, theRecordParent

-- open location "devonreveal://DATABASE/Path/to/record"

on open location theURL
	set {theScheme, thePath} to stringSplit(urlDecode(theURL), "://")
	set theDatabase to arrayToString(item 1 of stringSplit(thePath, "/"), "/")
	set theParent to "/" & arrayToString(items 2 thru -2 of stringSplit(thePath, "/"), "/") & "/"
	set theName to arrayToString(item -1 of stringSplit(thePath, "/"), "/")
	
	if theScheme is "devonreveal" then
		tell application id "DNtp"
			activate
			set theDatabase to first database whose name is theDatabase as string
			set theDatabaseUUID to uuid of theDatabase
			tell theDatabase
				set theRecord to get record at thePath
				if theRecord is missing value then
					try
						set theRecord to first content whose location is theParent and name is theName
					on error error_message number error_number
						if the error_number is -1719 then display alert "DEVONreveal" message "Record not found" as warning
						return
					end try
				end if
				set theRecordParent to get record at theParent
			end tell
			
			-- are there any viewer windows?	
			if exists viewer window 1 then
				-- bring existing database window to front
				repeat with theWindow in viewer windows
					if (uuid of database of root of theWindow) is uuid of theDatabase then
						if index of theWindow is 1 then exit repeat
						set visible of theWindow to false
						set visible of theWindow to true
						exit repeat
					end if
				end repeat
				-- open new window when the database is not visible in the front most viewer
				if (uuid of database of root of viewer window 1) is not uuid of theDatabase then
					open window for record (current group) of theDatabase
				end if
			else -- open a new window if there's no viewer window
				open window for record (current group) of theDatabase
			end if
			
			-- set root to the parent of the document
			set root of viewer window 1 to theRecordParent
			-- select the record
			set selection of viewer window 1 to {theRecord}
			
			-- alternative code
			--set theTab to open tab for record theRecord in think window 1
			--set current tab of think window 1 to theTab
		end tell
	end if
end open location

on stringReplace(subjectStr, findStr, replaceStr)
	set orgDelims to text item delimiters of AppleScript
	set text item delimiters of AppleScript to findStr
	set resultStr to text items of subjectStr
	set text item delimiters of AppleScript to replaceStr
	set resultStr to the resultStr as string
	set text item delimiters of AppleScript to orgDelims
	return resultStr
end stringReplace

on stringSplit(subjectStr, splitStr)
	if subjectStr does not contain splitStr then return subjectStr
	set orgDelims to text item delimiters of AppleScript
	set text item delimiters of AppleScript to splitStr
	set subjectStr to text items of subjectStr
	set text item delimiters of AppleScript to orgDelims
	return subjectStr
end stringSplit

on arrayToString(subjectArr, splitStr)
	set orgDelims to text item delimiters of AppleScript
	set text item delimiters of AppleScript to splitStr
	set subjectStr to subjectArr as string
	set text item delimiters of AppleScript to orgDelims
	return subjectStr
end arrayToString

on urlDecode(theText)
	set sDst to ""
	
	-- simple unicode normalisation
	set theText to stringReplace(theText, "a%CC%80", "à")
	set theText to stringReplace(theText, "a%CC%81", "á")
	set theText to stringReplace(theText, "e%CC%81", "é")
	set theText to stringReplace(theText, "e%CC%80", "è")
	set theText to stringReplace(theText, "a%CC%88", "ä")
	set theText to stringReplace(theText, "A%CC%88", "Ä")
	set theText to stringReplace(theText, "o%CC%88", "ö")
	set theText to stringReplace(theText, "O%CC%88", "Ö")
	set theText to stringReplace(theText, "u%CC%88", "ü")
	set theText to stringReplace(theText, "U%CC%88", "Ü")
	set theText to stringReplace(theText, "%C3%A0", "à")
	set theText to stringReplace(theText, "%C3%A1", "á")
	set theText to stringReplace(theText, "%C3%A9", "é")
	set theText to stringReplace(theText, "%C3%A8", "è")
	set theText to stringReplace(theText, "%C3%A4", "ä")
	set theText to stringReplace(theText, "%C3%84", "Ä")
	set theText to stringReplace(theText, "%C3%B6", "ö")
	set theText to stringReplace(theText, "%C3%96", "Ö")
	set theText to stringReplace(theText, "%C3%BC", "ü")
	set theText to stringReplace(theText, "%C3%9C", "Ü")
	set theText to stringReplace(theText, "%C3%9F", "ß")
	
	set sHex to "0123456789ABCDEF"
	set i to 1
	repeat while i ≤ length of theText
		set c to character i of theText
		if c = "+" then
			set sDst to sDst & " "
		else if c = "%" then
			if i > ((length of theText) - 2) then
				display dialog ("Invalid URL Encoded string - missing hex char") buttons {"Crap..."} with icon stop
				return ""
			end if
			set iCVal1 to (offset of (character (i + 1) of theText) in sHex) - 1
			set iCVal2 to (offset of (character (i + 2) of theText) in sHex) - 1
			if iCVal1 = -1 or iCVal2 = -1 then
				display dialog ("Invalid URL Encoded string - not 2 hex chars after % sign") buttons {"Crap..."} with icon stop
				return ""
			end if
			set sDst to sDst & (ASCII character (iCVal1 * 16 + iCVal2))
			set i to i + 2
		else
			set sDst to sDst & c
		end if
		set i to i + 1
	end repeat
	return sDst
end urlDecode

Save it as an Applet and add this to the Info.plist:

	<key>CFBundleURLTypes</key>
	<array>
		<dict>
			<key>CFBundleURLName</key>
			<string>Reveal URL scheme for DEVONthink</string>
			<key>CFBundleURLSchemes</key>
			<array>
				<string>devonreveal</string>
			</array>
		</dict>
	</array>

Launch the Applet once and the URL scheme should be active:

devonreveal://DATABASE/Path/to/record