← back to posts

Flexible document numbering (ASN) with DevonThink

The Problem

I digitize every important physical document and organize it in the extremely powerful DevonThink. I rarely need the physical copy—retrieving the digital version is faster and easier. To bridge the physical and digital worlds and be able to find the physical document when needed, I assign a unique number to each document and write it on both versions.

The great Paperless project calls this ASN (archive serial number).

DevonThink Standard functionality

To assign an ASN, I use DevonThink’s alias and Imprinter feature (Settings → Imprinter) to embed the identifier in the digital file and make it searchable. I assign an alias via a smart rule and trigger the imprinter from there, too.

DevonThink provides several numbering options:

The issues I have with Bates Numbering are:

The Solution

Continue using the Imprinter and add a Smart Rule that sets aliases via a JavaScript for Automation (JXA) script.

This script

// Import Foundation framework
ObjC.import('Foundation');

// Configurable key name for the counter in the plist
const COUNTER_KEY = "ASN";

// Resolve full path to the property list file
let nsPath = $("~/Databases/Numbering.plist").stringByStandardizingPath;

/**
 * Converts a property list (plist) string into an NSDictionary
 */
function propertyListToDictionary(plist) {
  const data = $(plist).dataUsingEncoding($.NSUTF8StringEncoding);
  const err = Ref();
  const format = Ref();

  return $.NSPropertyListSerialization.propertyListWithDataOptionsFormatError(
    data,
    {},
    format,
    err
  );
}



/**
 * Updates aliases in each record with a running counter and saves back the counter
 */
function performsmartrule(records) {
  const app = Application.currentApplication();
  app.includeStandardAdditions = true;

  // Load and parse plist contents
  let contents = $.NSString.stringWithContentsOfFileEncodingError(
    nsPath,
    $.NSUTF8StringEncoding,
    null
  );

  // Read the full dictionary and unwrap it
  let fullDict = ObjC.deepUnwrap(propertyListToDictionary(contents));

  // Extract and track the current counter, set to 1 if cannot be read. 
  let counter = fullDict[COUNTER_KEY] || 1;

  records.forEach(r => {
    let al = r.aliases();
    r.aliases = (al.length > 0 ? al + ", " : "") + COUNTER_KEY + " " + counter;
    counter++;
  });

   // Update the counter in the original dictionary
  fullDict[COUNTER_KEY] = counter;

  // Write the updated dictionary back to the file
  let updatedDict = $.NSDictionary.dictionaryWithDictionary(fullDict);
  updatedDict.writeToFileAtomically(nsPath, true);
}

Create an imprinter that imprints the alias on the document, and a smart rule that sets the alias, and then imprints. Write the resulting ASN on your physical document and be always able to reference between both copies.

subscribe to feed