Compatibility with Hook Productivity on Mac OS

I don’t know how folks usually share and track their Hook scripts, but I pushed mine up to GitHub: technicalpickles/obsidian-hook-scripts

@ldebritto I don’t have any accented characters in notes yet, but I can take a look. Is that screenshot from Hook when you go to link? Does it display correctly in Obsidian?

3 Likes

Actually both scripts (Name and URL) fail on accented characters.

The screenshot from hook is this:
Captura de Tela 2020-12-01 às 16.42.43

On Obsidian, it fails to retrieve the correct note:
Captura de Tela 2020-12-01 às 16.42.28

That also will happen with Emoji on note titles.

I’ll mark your Git repo as watched!

Looked into it a bit, and I think this might be an Obsidian bug? I’m pulling things from .obsidian/workspace (which is a JSON file), and the filename in lastOpenFiles has the bad characters instead of the accents.

It looks like like the metadata cache in ~/Library/Application Support/obsidian/ObsidianCache/<vault id>.json has the correct characters though. I’m not sure if there’s any way to work around it, since that is keyed by the filename, and the last file we know the name on is wrong :thinking:

It looks ok on my lastOpenFiles list. Have a look into this screenshot from the file on BBEdit:

I wonder if there’s something going wrong on the on the parsing to URL format section of the script.

Using AppleScript and two handlers (one for JSON Parsing and other for URL encoding, both from stackoverflow), I’ve managed to make a version that will work following the same @technicalpickles specifications for getting the URL.

As a known but very likely workable limitation, I couldn’t make the script work properly with multiple vaults, and thus there’s a segment still in progress. Somebody with better AppleScript knowledge could possibly make a better job here.

This is the Get URL script:

# GOAL
-- Fetches an Obsidian URI link trough AppleScript on the background

-- Known limitations: currently works only with one vault

# WORKFLOW
-- Step 0: replace selected variables with your own data
-- Step 1A: gets last vault from Obsidian JSON
-- Step 1B: gets last file relative path via parsing of JSON
-- Step 2: encodes the relative path to URL format
-- Step 3: generates obsidian link

# HANDLERS
-- Uses a JSONtoRecord handler from user CJK posted at Stackoverflow (https://stackoverflow.com/a/51623993/13936032)
use framework "Foundation"
use scripting additions
--------------------------------------------------------------------------------
property ca : a reference to current application
property NSData : a reference to ca's NSData
property NSDictionary : a reference to ca's NSDictionary
property NSJSONSerialization : a reference to ca's NSJSONSerialization
property NSString : a reference to ca's NSString
property NSUTF8StringEncoding : a reference to 4
--------------------------------------------------------------------------------
on JSONtoRecord from fp
	local fp
	
	set JSONdata to NSData's dataWithContentsOfFile:fp
	
	set [x, E] to (NSJSONSerialization's ¬
		JSONObjectWithData:JSONdata ¬
			options:0 ¬
			|error|:(reference))
	
	if E ≠ missing value then error E
	
	tell x to if its isKindOfClass:NSDictionary then ¬
		return it as record
	
	x as list
end JSONtoRecord
--------------------------------------------------------------------------------

-- This second handler encodes the URL format without errors
on urlEncode(input)
	tell current application's NSString to set rawUrl to stringWithString_(input)
	set theEncodedURL to rawUrl's stringByAddingPercentEscapesUsingEncoding:4 -- 4 is NSUTF8StringEncoding
	return theEncodedURL as Unicode text
end urlEncode

# START OF THE STEPS
(*
# IN PROGRESS - STEP 1A - Gets lastVault Name and Path data from obsidian.json at home folder
-- Gets the last vault JSON info
set home to the path to home folder
set v to the POSIX path of home & "Library/Application Support/obsidian/obsidian.json"
set JSONVaultRecord to JSONtoRecord from v
set lastVaultID to last_open of JSONVaultRecord
set lastVault to lastVaultID of vaults of JSONVaultRecord

set vaultPath to |path| of lastVault
*)

# STEP 1B - Gets user inputted vault Name and Path
set vaultName to "Obsidian"
set vaultPOSIXPath to "/Users/xxx/Documents/Obsdian/"


# STEP 2 - Gets relative path to lastOpenFile
-- Gets the workspace JSON file
set f to vaultPOSIXPath & ".obsidian/workspace"
set JSONFilesRecord to JSONtoRecord from f
set lastOpenFile to item 1 of lastOpenFiles of JSONFilesRecord


# STEP 3 - Encodes the relative path to a URL-friendly format
set encodedRelativePath to urlEncode(lastOpenFile)


# STEP 4 - Mounts the URI scheme link from variables vaultName and encodedRelativePath
set obsidianURL to "obsidian://open?vault=" & vaultName & "&file=" & encodedRelativePath

return obsidianURL

This is the Get Name script:

# GOAL
-- Fetches an Obsidian URI link trough AppleScript on the background

-- Known limitations: currently works only with one vault

# WORKFLOW
-- Step 0: replace selected variables with your own data
-- Step 1A: gets last vault from Obsidian JSON
-- Step 1B: gets last file relative path via parsing of JSON
-- Step 2: encodes the relative path to URL format
-- Step 3: generates obsidian link

# HANDLERS
-- Uses a JSONtoRecord handler from user CJK posted at Stackoverflow (https://stackoverflow.com/a/51623993/13936032)
use framework "Foundation"
use scripting additions
--------------------------------------------------------------------------------
property ca : a reference to current application
property NSData : a reference to ca's NSData
property NSDictionary : a reference to ca's NSDictionary
property NSJSONSerialization : a reference to ca's NSJSONSerialization
property NSString : a reference to ca's NSString
property NSUTF8StringEncoding : a reference to 4
--------------------------------------------------------------------------------
on JSONtoRecord from fp
	local fp
	
	set JSONdata to NSData's dataWithContentsOfFile:fp
	
	set [x, E] to (NSJSONSerialization's ¬
		JSONObjectWithData:JSONdata ¬
			options:0 ¬
			|error|:(reference))
	
	if E ≠ missing value then error E
	
	tell x to if its isKindOfClass:NSDictionary then ¬
		return it as record
	
	x as list
end JSONtoRecord
--------------------------------------------------------------------------------

-- This second handler encodes the URL format without errors
on urlEncode(input)
	tell current application's NSString to set rawUrl to stringWithString_(input)
	set theEncodedURL to rawUrl's stringByAddingPercentEscapesUsingEncoding:4 -- 4 is NSUTF8StringEncoding
	return theEncodedURL as Unicode text
end urlEncode

(*
# IN PROGRESS STEP 1A - Gets lastVault Name and Path data from obsidian.json at home folder
-- Gets the last vault JSON info
set home to the path to home folder
set v to the POSIX path of home & "Library/Application Support/obsidian/obsidian.json"
set JSONVaultRecord to JSONtoRecord from v
set lastVaultID to last_open of JSONVaultRecord
set lastVault to lastVaultID of vaults of JSONVaultRecord

set vaultPath to |path| of lastVault
*)

# STEP 1B - Gets user inputted vault Name and Path
set vaultName to "Obsidian"
set vaultPOSIXPath to "/Users/xxx/Documents/Obsdian/"


# STEP 2 - Gets relative path to lastOpenFile
-- Gets the workspace JSON file
set f to vaultPOSIXPath & ".obsidian/workspace"
set JSONFilesRecord to JSONtoRecord from f
set lastOpenFile to item 1 of lastOpenFiles of JSONFilesRecord


# STEP 3 - Encodes the relative path to a URL-friendly format
set encodedRelativePath to urlEncode(lastOpenFile)


# STEP 4 - Mounts the URI scheme link from variables vaultName and encodedRelativePath
set obsidianURL to "obsidian://open?vault=" & vaultName & "&file=" & encodedRelativePath

set fileName to name of (info for (vaultPOSIXPath & lastOpenFile))
return fileName```

It’s great to see all this integration happening. We’ve been looking at this at CogSci Apps and looking to incorporate support based on this.

I noticed something about Obsidian’s URL handling (nothing to do with the integration scripts). If I

  1. copy a URL of a file using Obsidian itself.
  2. rename the file in Obsidian itself ,i.e using the Obsidian UI, (not even via Finder),
  3. attempt to use the URL from step 1

result:

Obsidian cannot resolve the URLs.

Looking at the obsidian URL, it does not contain an ID.

Am I missing something?

hook://file/ URLs are robust under file renames, so we will likely, in addition to these scripts, provide alternative scripts that traffic in hook://file/ URLs.

Also, I’ve asked our devs at CogSci Apps to ensure Reveal File in Finder works via Hook in the context of Obsidian.

5 Likes

FYI Hook integration scripts v. 139 now available — Initial support for Obsidian! - Releases - Hook Productivity Forum With thanks to @technicalpickles for the JS and to @lsieverts , @Haberjr and everyone else who’s contributed to the discussion. That’s available via Hook’s in app software update mechanism.

Hook 2.1 ( hopefully coming later today or tomorrow) will also have this integration built in too, along with support for Apple Notes etc.

We’ve also created a dedicated page re Using Hook with Obsidian.

You’ll notice in those docs that we intend to update the integration (e.g., providing Reveal File in Finder , supporting Hook to New > Obsidian document , and giving users the option to use hook://file/ URLs, to the extent the Obsidian API allows.) We look forward to further development of the Obsidian API to automate linking from Obsidian to anything.

8 Likes

I want to thank @LucCogZest for his tremendous customer service. How many times have you seen a software company leader paying attention to this extent – joining us here on the Obsidian Forum? I look forward to the future of Hook.
:clap: :100: :heart:

7 Likes

I updated to Obsidian v0.10.0 this morning and it appears that the Hook integration has been broken. Anyone else have that issue?

Same here. Seems to be something with the javascript code rather than with the Obsidian system files.

Reverted back to my Rube Golbergian AppleScript implementation above and its working fine on my end.

1 Like

Same here. The issue seems to be with const vaultPath = vault["path"]. For a quick fix, I manually set the path for const workspaceJSONPath & vaultId

1 Like

Confirmed the javascript is not working.

It looks like obsidian.json no longer has the lastOpen field. I haven’t looked over the guess the Applescript version was not using that? Now there’s an "open": true on the vaults under “vaults” though:

{
  "vaults": {
    "e785b2424ba22046": {
      "path": "/path/to/pickled-knowledge/pickled-knowledge",
      "ts": 1607973379112,
      "open": false
    },
    "5a15e759232abbfe": {
      "path": "/Users/technicalpickles/Library/Application Support/obsidian/Obsidian Help",
      "ts": 1607973060335
    }
  },
  "insider": true
}

It shouldn’t be too hard to fix, and it should be possible to support both versions for a little bit at least.

Indeed! I wasn’t looking for the lastOpen vault, using an arbitrary variable with the path to my only vault.

My AppleScript skills weren’t good enough to fetch the lastOpen vault reliably (though I’ve managed to convert the JSON to a AppleScript record, I’m failing to check fetch the path to the record with the open key).

I guess the open:true is a safe step if there’s only one vault open at the time.

Is it possible to give quick instructions on how to fix this? Looks like maybe I can just manually set a path?

1 Like

We’ve updated Hook integration scripts to work with the latest insider build of Obsidian (v0.1), maintaining compatibility with the prior one. Details here: Hook integration scripts v.141 now available — Updated Obsidian support - Releases - Hook Productivity Forum. Thanks for notifying us/ interacting about the issue. Delighted to be able to help link Obsidian notes to anything again.

post Updated 2020-12-17 23:42 PT to refer to “v141” not “v142”.

6 Likes

I am now at 0.10.1 and Hook is working as expected. No problems

4 Likes

Thanks for making this a reality!

2 Likes

This is wonderful. Thanks for making this work!

3 Likes

@technicalpickles @ldebritto

We will soon stop using the json file for ObsidianCache and migrate to IndexedDB for performance reasons.

I think this will break your integration.
If you want to keep the current integration, I suggest you write a plugin that dumps the information you need in a file and read that.

2 Likes

Hello all,

Hook is looking into Obsidian. Please get in contact with them. See here:

https://discourse.hookproductivity.com/t/re-hook-to-new-obsidian/2993

Thanks!

2 Likes