Hi folks,
this script imports a Finder folder including aliases and resolves them to replicants.
It
- initiates a standard DEVONthink import
which imports files and subfolders but no aliases, so afterwards the script
- gets all aliases
- resolves them
- checks whether the alias’s original file or folder was already imported
if so it
- creates replicants
if not it
- creates bookmarks
- and a Smart Group.
So what’s in your Finder folder is either
- imported
- replicated or
- referenced.
Bookmarks are created if an alias points to a path outside the imported folder, only in this case the Smart Group is created and opened at the end. Opening it automatically acts as reminder that not all files or folders were imported. In case of bookmarks for PDFs or images the content can be viewed directly in DEVONthink, in case of bookmarks for folders make sure to open them via Data > Launch URL
, if you double click them they are added to the download manager.
A second script lets you import the bookmarks if need be, if that worked the bookmark gets label 2/green, if it failed it’s label 1/red (e.g. original deleted or an unmounted disk). If you import a folder and it contains aliases make sure to check the Smart Group again and import what’s necessary. However bookmarks should only act as a reminder in the first place, it’s not meant to import everything
Skipped aliases:
Aliases resolved to replicants:
Script: Import, resolve Finder aliases to replicants and reference external aliases
-- Import, resolve Finder aliases to replicants and reference external aliases
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
tell application id "DNtp"
try
activate
set thePath to POSIX path of (choose folder with prompt "Choose folder" default location (path to desktop folder) without invisibles)
set theGroup to import thePath to display group selector
set theDatabase to database of theGroup
set theLocationAndName to ((location of theGroup) & my replaceString(((name of theGroup) as string), "/", "\\/")) as string
set createSmartGroup to false
repeat with i in {true, false}
set theAliasPaths_record to my getDescendingAliasPaths(thePath, i as boolean)
repeat with thisItem in theAliasPaths_record
set theAliasParent_Location to (theLocationAndName & "/" & my replaceString(pathParent of thisItem, thePath, "")) as string
set theAliasParent_Group to create location theAliasParent_Location in theDatabase
set theOriginalPath to pathOriginal of thisItem
if theOriginalPath starts with thePath then
set theAliasOriginal_Location to (theLocationAndName & "/" & my replaceString(pathOriginal of thisItem, thePath, "")) as string
if (exists record at theAliasOriginal_Location in theDatabase) then
set theAliasOriginal_Group to get record at theAliasOriginal_Location in theDatabase
replicate record theAliasOriginal_Group to theAliasParent_Group
else
import pathOriginal of thisItem to theAliasParent_Group
end if
else
set {theName, theURL, thePOSIXPath} to {item 1, item 2, item 3} of my getFileProperties(pathOriginal of thisItem)
create record with {name:theName, URL:theURL, type:bookmark, comment:thePOSIXPath} in theAliasParent_Group
set createSmartGroup to true
end if
end repeat
end repeat
if createSmartGroup = true then
set theSmartGroup to create record with {type:smart group, search predicates:"url:file:///", name:"-- Not imported --"} in theGroup
set search group of theSmartGroup to theGroup -- this is a necessary workaround in DEVONthink 3.6
open window for record theSmartGroup
activate
end if
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 getDescendingAliasPaths(thePath, isDirectory)
try
-- Based on: https://forum.latenightsw.com/t/searching-for-alias-files-recursively-not-descending-into-packages/1997/5
set theFolderURL to current application's class "NSURL"'s fileURLWithPath:thePath
set isAliasKey to current application's NSURLIsAliasFileKey
set isDirectoryKey to current application's NSURLIsDirectoryKey
set theFileManager to current application's NSFileManager's defaultManager()
set allURLs to (theFileManager's enumeratorAtURL:theFolderURL includingPropertiesForKeys:{isAliasKey} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + ((current application's NSDirectoryEnumerationSkipsHiddenFiles) as integer)) errorHandler:(missing value))'s allObjects()
set theAliasPaths_record to {}
repeat with thisURL in allURLs
set aliaskeyValue to end of (thisURL's getResourceValue:(reference) forKey:isAliasKey |error|:(missing value))
if (aliaskeyValue as boolean) = true then
set thisURL_path to (thisURL's valueForKeyPath:"path")
set thisOriginalURL_path to my resolveAlias(thisURL_path)
if thisOriginalURL_path ≠ missing value then
set thisOriginalURL to (current application's class "NSURL"'s fileURLWithPath:thisOriginalURL_path)
set directorykeyValue to end of (thisOriginalURL's getResourceValue:(reference) forKey:isDirectoryKey |error|:(missing value))
if (directorykeyValue as boolean) = isDirectory then
set thisParentURL_path to POSIX path of ((thisURL's valueForKeyPath:"URLByDeletingLastPathComponent") as string)
set end of theAliasPaths_record to {pathParent:thisParentURL_path, pathOriginal:thisOriginalURL_path}
end if
end if
end if
end repeat
return theAliasPaths_record
on error error_message number error_number
activate
display alert "Error: Handler \"getDescendingAliasPaths\"" message error_message as warning
error number -128
end try
end getDescendingAliasPaths
on resolveAlias(thePath)
try
set thePath_URL to (current application's class "NSURL"'s fileURLWithPath:thePath)
set thePath_Original_URL to (current application's class "NSURL"'s URLByResolvingAliasFileAtURL:thePath_URL options:0 |error|:(missing value))
if thePath_Original_URL ≠ missing value then set thePath_Original to (POSIX path of (thePath_Original_URL as string))
on error error_message number error_number
activate
display alert "Error: Handler \"resolveAlias\"" message error_message as warning
error number -128
end try
end resolveAlias
on replaceString(theText, oldString, newString)
try
set theString to current application's NSString's stringWithString:theText
set newString to theString's stringByReplacingOccurrencesOfString:oldString withString:newString
return newString as string
on error error_message number error_number
activate
display alert "Error: Handler \"replaceString\"" message error_message as warning
error number -128
end try
end replaceString
on getFileProperties(thePath)
tell application "System Events"
try
set theItem to disk item thePath
set theName to name of theItem
if class of theItem = folder then set theName to "_Folder: " & theName
set theURL to URL of theItem
set thePOSIXPath to POSIX path of theItem
return {theName, theURL, thePOSIXPath}
on error error_message number error_number
activate
display alert "Error: Handler \"getFileProperties\"" message error_message as warning
error number -128
end try
end tell
end getFileProperties
Script: Import via bookmark, resolve Finder aliases to replicants and reference external aliases
-- Import via bookmark, resolve Finder aliases to replicants and reference external aliases
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
tell application id "DNtp"
try
if not (exists think window 1) then error "Please select a record"
set theRecords to selection of think window 1
if theRecords = {} then error "Please select a record"
repeat with thisRecord in theRecords
set thisURL to URL of thisRecord
if thisURL starts with "file:///" then
set theURL to (current application's class "NSURL"'s URLWithString:thisURL)
if theURL ≠ missing value then
set theURL_path to (theURL's valueForKeyPath:"path") as string
set theGroup to import theURL_path to (parent 1 of thisRecord)
set theDatabase to database of theGroup
set theLocationAndName to ((location of theGroup) & my replaceString(((name of theGroup) as string), "/", "\\/")) as string
set createSmartGroup to false
repeat with i in {true, false}
set theAliasPaths_record to my getDescendingAliasPaths(theURL_path, i as boolean)
repeat with thisItem in theAliasPaths_record
set theAliasParent_Location to (theLocationAndName & "/" & my replaceString(pathParent of thisItem, theURL_path, "")) as string
set theAliasParent_Group to create location theAliasParent_Location in theDatabase
set theOriginalPath to pathOriginal of thisItem
if theOriginalPath starts with theURL_path then
set theAliasOriginal_Location to (theLocationAndName & "/" & my replaceString(pathOriginal of thisItem, theURL_path, "")) as string
if (exists record at theAliasOriginal_Location in theDatabase) then
set theAliasOriginal_Group to get record at theAliasOriginal_Location in theDatabase
replicate record theAliasOriginal_Group to theAliasParent_Group
else
import pathOriginal of thisItem to theAliasParent_Group
end if
else
set {theName, theURL, thePOSIXPath} to {item 1, item 2, item 3} of my getFileProperties(pathOriginal of thisItem)
create record with {name:theName, URL:theURL, type:bookmark, comment:thePOSIXPath} in theAliasParent_Group
set createSmartGroup to true
end if
end repeat
end repeat
if createSmartGroup = true then
set theSmartGroup to create record with {type:smart group, search predicates:"url:file:///", name:"-- Not imported --"} in theGroup
set search group of theSmartGroup to theGroup -- this is a necessary workaround in DEVONthink 3.6
open window for record theSmartGroup
activate
end if
set label of thisRecord to 2
else
set label of thisRecord to 1
end if
end if
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 getDescendingAliasPaths(thePath, isDirectory)
try
-- Based on: https://forum.latenightsw.com/t/searching-for-alias-files-recursively-not-descending-into-packages/1997/5
set theFolderURL to current application's class "NSURL"'s fileURLWithPath:thePath
set isAliasKey to current application's NSURLIsAliasFileKey
set isDirectoryKey to current application's NSURLIsDirectoryKey
set theFileManager to current application's NSFileManager's defaultManager()
set allURLs to (theFileManager's enumeratorAtURL:theFolderURL includingPropertiesForKeys:{isAliasKey} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + ((current application's NSDirectoryEnumerationSkipsHiddenFiles) as integer)) errorHandler:(missing value))'s allObjects()
set theAliasPaths_record to {}
repeat with thisURL in allURLs
set aliaskeyValue to end of (thisURL's getResourceValue:(reference) forKey:isAliasKey |error|:(missing value))
if (aliaskeyValue as boolean) = true then
set thisURL_path to (thisURL's valueForKeyPath:"path")
set thisOriginalURL_path to my resolveAlias(thisURL_path)
if thisOriginalURL_path ≠ missing value then
set thisOriginalURL to (current application's class "NSURL"'s fileURLWithPath:thisOriginalURL_path)
set directorykeyValue to end of (thisOriginalURL's getResourceValue:(reference) forKey:isDirectoryKey |error|:(missing value))
if (directorykeyValue as boolean) = isDirectory then
set thisParentURL_path to POSIX path of ((thisURL's valueForKeyPath:"URLByDeletingLastPathComponent") as string)
set end of theAliasPaths_record to {pathParent:thisParentURL_path, pathOriginal:thisOriginalURL_path}
end if
end if
end if
end repeat
return theAliasPaths_record
on error error_message number error_number
activate
display alert "Error: Handler \"getDescendingAliasPaths\"" message error_message as warning
error number -128
end try
end getDescendingAliasPaths
on resolveAlias(thePath)
try
set thePath_URL to (current application's class "NSURL"'s fileURLWithPath:thePath)
set thePath_Original_URL to (current application's class "NSURL"'s URLByResolvingAliasFileAtURL:thePath_URL options:0 |error|:(missing value))
if thePath_Original_URL ≠ missing value then set thePath_Original to (POSIX path of (thePath_Original_URL as string))
on error error_message number error_number
activate
display alert "Error: Handler \"resolveAlias\"" message error_message as warning
error number -128
end try
end resolveAlias
on replaceString(theText, oldString, newString)
try
set theString to current application's NSString's stringWithString:theText
set newString to theString's stringByReplacingOccurrencesOfString:oldString withString:newString
return newString as string
on error error_message number error_number
activate
display alert "Error: Handler \"replaceString\"" message error_message as warning
error number -128
end try
end replaceString
on getFileProperties(thePath)
tell application "System Events"
try
set theItem to disk item thePath
set theName to name of theItem
if class of theItem = folder then set theName to "_Folder: " & theName
set theURL to URL of theItem
set thePOSIXPath to POSIX path of theItem
return {theName, theURL, thePOSIXPath}
on error error_message number error_number
activate
display alert "Error: Handler \"getFileProperties\"" message error_message as warning
error number -128
end try
end tell
end getFileProperties