Archive group: Script to create new database with selected group and archive new database

Here’s how it can be done in AppleScriptObjC

-- Get plain text from RTF(D) Custom Meta Data

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

property theCMD_Identifier : "testrtf" -- set your Custom Meta Data identifier

tell application id "DNtp"
	try
		set theRecords to selected records
		if theRecords = {} then error "Please select some records."
		
		repeat with thisRecord in theRecords
			set thisRecord_CMD_RTF to get custom meta data for theCMD_Identifier from thisRecord
			
			if thisRecord_CMD_RTF ≠ missing value then
				set thisRecord_CMD_RTF_plainText to my getPlainTextFromRTFDdata(thisRecord_CMD_RTF)
			else
				set thisRecord_CMD_RTF_plainText to ""
			end if
			
			-- do something with variable "thisRecord_CMD_RTF_plainText"
			
		end repeat
		
	on error error_message number error_number
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell


on getPlainTextFromRTFDdata(theData)
	try
		set theNSData to (current application's NSArray's arrayWithObject:theData)'s firstObject()'s |data|()
		set {theAttributedString, theError} to (current application's NSAttributedString's alloc()'s initWithData:theNSData options:(missing value) documentAttributes:(missing value) |error|:(reference))
		if theError ≠ missing value then error (theError's localizedDescription() as string)
		set theString to theAttributedString's |string|()
		return theString as string
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"getPlainTextFromRTFDdata\"" message error_message as warning
		error number -128
	end try
end getPlainTextFromRTFDdata
1 Like

Ok, thanks so much. Will try to enhance that…

I’ll never used JS in Devonthink. The documentation says it cannot be used like AppleScript. So can JS only be used in smart rules?

Documentation >

JavaScript: In addition to AppleScript, JavaScript for Automation (JXA) is supported. However, it is bridged by the operating system from AppleScript, not specifically coded for.

JXA is supported in scripts, not just smart rules. But we do not create a script definition file for it. The scripting definition is for AppleScript but it’s converted when switching the scripting language to JavaScript.

1 Like

Sure, of course! :man_facepalming: Sorry!

Thanks for that. I’d of course like to replicate that in JXA, but I’m stumbling upon this line:

(current application's NSArray's arrayWithObject:theData)'s firstObject()
should be a (variant of) NSString. Or at least it is when I rewrite that line in JavaScript. But I don’t understand what the |data|() at the end is doing. It looks like a function/method call for data, but I don’t find that function/method in NSString. Simply replicating the code as

const nsdata = $.NSArray.arrayWithObject(theData).firstObject.data;

gives me a nil object.

Never cared about what it’s needed for, but turns out someone in the thread asked exactly that. Here’s Shane’s explanation:

When you create an array, any non-bridgeable AS items in it get converted to NSAppleEventDescriptors. So it’s effectively calling the -data method on an event descriptor.

(https://forum.latenightsw.com/t/convert-nsdata-into-raw-data-string/1914/7)

The only difference I can see between my AppleScript and your JavaScript is that I got brackets around the array part. What do you get when you use

const nsdata = $.NSArray.arrayWithObject(theData)

? What’s in the array?

an NSCFSting. It seems that we’re seeing again a problem that has arisen before: JXA receives a simple string from OSA, while AppleScript gets something special that can then be converted into a NSData object.

No worries! An easy misunderstanding.

Just to get some kind of closure here:

  • JavaScript and AppleScript are both based on Apple’s Open Scripting Architecture (OSA)
  • DEVONtechnologies even published a blog entry on using JXA with DT: DEVONtechnologies | How to Use JavaScript for Automation
  • Therefore, I find the wording in the documentation a bit awkward (JavaScript is, afaik, not bridged from AS, btw).
  • AppleScript is the older language, and it’s considered by many to be easier to learn
  • AppleScript is lacking a strict syntax definition
  • JavaScript is newer, it’s in use everywhere now (Web, desktop, whatever), but considered by many more difficult to learn
  • JavaScript is constantly developed by a standardization body and has a strict syntax definition.
  • Both are more or less dead in the water in terms of OSA: Apple is not doing anything with/to them anymore.
  • JavaScript for Automation (i.e. the OSA incantation of JavaScript) has never been finished, much less polished. There are some things that should work but don’t
  • One is the case of “formatted text in custom metadata”: In AppleScript, the value is an AppleEvent(Descriptor?) that can be converted to a string, as @pete31 demonstrated.
  • This doesn’t work in JXA (at least I can’t make it work). The only workaround would be to call the AppleScript code from JXA, which in fact works just fine.

Since producing JSON is a lot easier in JavaScript, I’d still suggest to stick with that for your purpose. If need be, we can continue the discussion in private.

1 Like

Today i had a little time to start this “project” …

Starting with the Applescript:

tell application id "DNtp"

	set selectedGroup to item 1 of (get selection)
	
	set documentsPath to path to desktop
	
	set dtaFolder to documentsPath & "Aktenablage"
	if not (exists dtaFolder) then
		make new folder at documentsPath with properties {name:Aktenablage}
	end if
	
	set newDatabase to create database with properties {name:(name of selectedGroup), path:dtaFolder as alias}

end tell

Result is a syntax error in the last line. If i remove the properties result is “missing value”…

Could someone give me an advice? Thanks…

Did you check that the various variables are what you want them to be? Running the code in Script Editor with its protocol tab active helps in figuring that out.

And perhaps the name parameter of the male should be a string? But I guess this branch of the code has not been executed.

Thanks for your help…

Creating the database with the name of the selected group works for me with:

tell application id "DNtp"
	set selectedGroup to item 1 of (get selection)
	set groupName to name of selectedGroup
	set desktopPath to POSIX path of (path to desktop) & groupName & ".dtbase2"
	set newDatabase to create database desktopPath
end tell

I’m assuming encrypted databases can’t be created via Applescript. Correct?

But is it possible to disable the spotlight index via Applescript?

Note: Your desktop isn’t a good permanent location for databases and working files.

I’m assuming encrypted databases can’t be created via Applescript. Correct?

That is correct. There is no direct command for this. And the encrypted property is read only.

But is it possible to disable the spotlight index via Applescript?

No. There is not a property for this.

We’ll consider this for future releases.

Also setting up username and password for importing/syncing should be possible via script.

Thanks a lot!

I respectfully disagree. Passwords should never, ever be set in clear text in a script. Did I say never?

You presumably want to encrypt your database to protect them from unauthorized access. Which, in your scenario, implies that someone might have access to your machine (how else would they be able to get at your databases). Which, in turn, means that they can read your scripts. Containing passwords? So, your scenario is that an authorized person is intelligent enough to find your databases, but too stupid to read your scripts? Seriously?

To reiterate: Never store your password in a script. Not in DT, not in Python, not in AppleScript. Never. I’d actually prefer no password “protection” at all. Instead, certificates, hardware keys, anything that is more difficult to guess and steal.

You’re right, of course, but it’s also possible to prompt for the name and password…

First off, I’m not sure what these “encrypted” databases really are. The manual says

Encrypted Databases: If you have databases containing sensitive or private information, you can create an encrypted database. This is specialized AES-256 encrypted disk image that will not appear in the Finder or your desktop when it’s open.

But @BLUEFROG stated that a password protected database is not encrypted:

Regardless: I’d still rather use some hardware protection than a password, if I had to. Passwords can be brute-forced or guessed.

To clarify… there are three ways to protect the database or sync:

  1. Encrypted database (AES-256 encrypted disk image > .dtSparse): The database is fully encrypted on local disk on a dmg-Volume. Without the password you cannot open the database.

  2. Password protection for importing (set up in database properties): Asks for name and password if you want to import the database from sync location. Without the credentials you cannot import a database from a sync location.

  3. Encryption with password protection for sync location itself (set up in sync location settings): Protects the sync location itself. Without the password you cannot join to a existing sync location.

1 Like