I use a service called SimpRead to read and annotate local HTML files in DEVONthink, generate permanent links, and save them to my notes. After configuring, I can view the HTML list in DEVONthink by opening the URL http://127.0.0.1:7026/static. Therefore, I want to write a Smart Rule to make it easier to directly open the selected HTML files in DEVONthink with SimpRead. I wrote a Smart Rule that matches all HTML files in the database and uses the following Apple Script code:
on urlencode(str)
local str
try
return (do shell script "/bin/echo " & quoted form of str & ÂŹ
" | perl -MURI::Escape -lne 'print uri_escape($_)'")
on error eMsg number eNum
error "Can't urlEncode: " & eMsg number eNum
end try
end urlencode
on performSmartRule(theRecords)
tell application id "DNtp"
set theSelection to the selection
repeat with theRecord in theSelection
set recPath to (path of theRecord)
set pattern to "\\.\\/html\\/(\\d+)\\/(.+\\.html)"
set newString to do shell script "echo " & quoted form of recPath & " | sed 's/" & pattern & "/\\1%2F\\2/'"
tell application "Google Chrome"
activate
open location "http://127.0.0.1:7026/static/" & urlencode(newString)
end tell
end repeat
end tell
end performSmartRule
However, this code does not run successfully, which is why I am seeking help here. In fact, I know very little about the code, and I obtained it by generating it through chatGPT, searching for posts on the DEVONtechonologies forum, and modifying it myself. I do not know how to debug in DEVONthink, and due to my limited coding ability, I have not been able to identify any syntax errors. Therefore, I am almost unable to make any modifications to the code to make it work properly. I would greatly appreciate any help I can get.
There are different approaches to solve your problem. Mine would be to start learning about these things and thus getting an understanding of the code. Which ChatGPT apparently has not.
A good starting point would be the fine DT manual. It has a section titled âAutomationâ where youâll find information on scripts, also on scripts for smart rules.
Another issue is that the script processes the selection but should use the theRecords parameter instead. Smart rules should never work on the selection, otherwise the results might not be the expected ones.
Do you mean I should replace the selection with theRecords, like this:
on urlencode(str)
local str
try
return (do shell script "/bin/echo " & quoted form of str & ÂŹ
" | perl -MURI::Escape -lne 'print uri_escape($_)'")
on error eMsg number eNum
error "Can't urlEncode: " & eMsg number eNum
end try
end urlencode
on performSmartRule(theRecords)
tell application id "DNtp"
repeat with theRecord in the records
set recPath to (path of theRecord)
set pattern to "\\.\\/html\\/(\\d+)\\/(.+\\.html)"
set newString to do shell script "echo " & quoted form of recPath & " | sed 's/" & pattern & "/\\1%2F\\2/'"
tell application "Google Chrome"
activate
open location "http://127.0.0.1:7026/static/" & urlencode(newString)
end tell
end repeat
end tell
end performSmartRule
I have actually tried it out, which still didnât work, either.
The selection thing was the obvious mistake. The next one is that the parameter of performSmartRule is theRecords and that you then use theRecord of the records. This line will probably not even survive the syntax check.
The rest is a lot less obvious, due to a lack of comments (canât or wonât ChatGPT illustrate what itâs trying to do?) and explanation from your side.
Firstly, I see a regular expression pattern \.html\/(\d+)\/\(.+\.html)
of which I have no idea what it is trying to achieve. It would match strings like â.html//.htmlâ and convert them into â/%2F.htmlâ Given that this is the path to a record, why are you so heavily modifying it, i.e. throwing away the first .html (and why would there even be two â.htmlâ extensions in this path)?
Secondly, Iâm not sure that I really understand how this Simple Read thingy works. It looks as if theyâre running a local web server at port 7026 and which shows you something (but what exactly?) at the location static. Your script appends something to this URI, namely a heavily modified path to a DT record. Did you try this concept in your browser? Did it work? What do the URLs really look like?
My take on that, with a simple script, not one to be used in a smart rule (and in JavaScript, of course):
Put that into script editor, set its language selector in the upper-left corner to âJavaScriptâ, select a record in DT and run the script in script editor. Its debug area will show you whatâs happening.
Thank u so much for your detailed reply!
SimpRead is able to read HTML files from a local folder. I have set it to read from â~/Databases/Info.dtBase2/Files.noindex/htmlâ, which is the path of the HTML folder in my primary database of DEVONthink. By opening the corresponding URL with SimpRead, you can generate a reading mode for the local HTML file, highlight text, and create a permanent deeplink for each highlighted annotation. You can also export it to note-taking software like Notion or Obsidian if needed. Once turning on the local server, the URL format that SimpRead reads for each HTML file in the folder is âhttp://127.0.0.1:7026/static/â + . For example, if I have an HTML file named âcubox_exportâ with a path of â./html/b/cubox_export.htmlâ, the URL that SimpRead will use to open it is âhttp://127.0.0.1:7026/static/b%2Fcubox_export.htmlâ.
I wonât have time to check that before afternoon CET. But I now understand what the regular expression tries to do: remove the path to the html document and leave only the file name itself. That might be achieved with something like this r.path().replace(/^.*?html/,"")
To get more detail in the script editor, open the debug page by clicking on the three lines at the bottom of the window. You can then follow in detail whatâs happening.
I now understand that the path of a record obtained by the script is an absolute path, while the path shown in DEVONthinkâs inspector is indeed a relative one, so the regular expression should be adjusted.
Well, if you have a look at the scripting dictionary for Chrome, there is no openLocation method (yeah, I hadnât checked either this morning, assuming someone would have done it. Stupid). Obviously, ChatGPT didnât look either, but just stammered somethingâ˘. Another good reason to just forget about this crap and learn to script if you need it. Thereâs no shortcut, except the one that leads you directly into a dead end.
OTOH: The replace does probably work in this case, but itâs not what one would do when using a regular expression. Instead, (and Iâd said that before, hadnât I?): /^.*?html
Why: Because your âREâ only works for one database, namely âInfoâ. Itâll fail for any other database, e.g. âTestâ because then the base path would contain âŚTest.dtBase2âŚ. And thatâs why the regular expression is called âregularâ: You use it to specify a pattern that is as specific as necessary and as broad as required. In this case, youâre looking for the beginning of the string (^), followed by any character (.) any number of times (*) followed by âhtmlâ literally. Now, this would gobble up the whole path because the filename ends with â.htmlâ. That is called âgreedy behaviorâ in a RE, and the question mark (?) turns it off. It basically says, âfind as much as necessary followed by âhtmlâ and then stopâ. Which will terminate the search after the âhtmlâ in the path, just before the sub-folder âbâ.
Aside: Script Editor is even worse than I thought. Instead of correctly displaying chrome its output when a method of this app is called, it uses app again, although thatâs clearly wrong and refers to another Application object. Why canât they even get the simple things right?
Thanks for your detailed instructions! I follow your script provided above and now it already works! Yet still a little problem, it would be even better if the URL can be opened in the active window as the newest tab, or it would now replace the first tab in the first window of Chrome. As for the programming skill, to be honest, I learn a little bit of the very basic syntax of JavaScript(text formatting, Regex, loops and iteration, etc.) yet still have very limited knowledge of it, so it could be quite hard for me to finish even such a stuff. Thank you for your patience and kind help. more than obliged!
Not to sound impolite, but thatâs the point about learning: getting your feet wet. Yes, it takes time.
I got you started and provided you with some pointers. Now check out the scripting dictionary, my lovely site on JXA and use your favorite search engine â opening a new tab should be easy.
Thatâs a good point. I directly made it for the âInfoâ database, I just didnât care much about it because I have only two databases and all the html files are in the âInfoâ now. Of course I can specify the pattern t o match all the databases yet it works well for me now. Although Iâm not that familiar with programming, I can still use the Regex quite freely in the general, though sometimes might seem kind of stupid.
Yeah, you have reason, Iâll take that next time Another point is that English is actually not my first language, so it would be kind of complicated for me especially when it involves many technical terminologies. Anyway, thank you so much for your help!!!