lol your new script stopped working again. Any idea how I can help to debug? For some reason it runs correctly in script editor but not correctly in hook
Seems have to change the identifier to pdfexpert
rather than pdfexpert://
this does the trick for me. thank you so much!
Ah, yes, although I think the new version is probably better than the old.
@LucB More generally I tried not specifying an identifier and returning a file:// link, but when I did that the link title was always the filename of the document even if the scripts returned a customised title (either as a separate Get Name script or by returning a markdown link from Get Address). Is that expected behaviour?
It would seem better to use the file:// scheme if possible because that would make the links cross-compatible to some degree with other PDF apps (e.g. the PDFPenPro deep links seem to encode a page number which PDF Expert can be made to open to). However at least for my purposes, I want the link title to have the page number so I can paste it into my notes!
There seems to be an issue on Hook’s side with specifying the name in this case. We will look into that.
I think you mean hook://file/
URLs? That’s what we use for the other PDF apps. We are looking into that.
Yes, this was what I meant!
Hello, Lawyerboy. I’ve tried your code but unfortunately it does not work for me. Is there any chance you might update or give me some advice? (I’m new around here
I am working on another version but need to iron out a couple of bugs on my own setup first!
These are the scripts I’m currently using.
Get Address
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property NSURLComponents : a reference to current application's NSURLComponents
property NSURLQueryItem : a reference to current application's NSURLQueryItem
property NSMutableDictionary : a reference to current application's NSMutableDictionary
property NSFileManager : a reference to current application's NSFileManager's defaultManager
property NSURL : a reference to current application's NSURL
--Get Address
on getPDFExpertFileURL()
local fileURL
set fileURL to missing value
tell application "System Events"
activate application "PDF Expert"
tell process "PDF Expert" to set showInFinder to menu item "Show in Finder" of menu 1 of menu bar item "File" of menu bar 1
set isEnabled to showInFinder's enabled
end tell
if isEnabled then
tell application "System Events" to tell process "PDF Expert" to click showInFinder
delay 0.1
tell application "Finder"
set openWindows to id of every window
set fileURL to URL of (selection as alias)
close (get (every window whose id of it is not in openWindows))
end tell
end if
tell application "System Events" to activate application "PDF Expert"
return fileURL
end getPDFExpertFileURL
on getPDFExpertName()
tell application "System Events" to return name of first window of process "PDF Expert"
end getPDFExpertName
on getPageDetails()
set {pageNo, pageLabel} to {missing value, missing value}
try --Get the details we need
tell application "System Events" to tell process "PDF Expert"
set pageNoText to value of static text 1 of splitter group 1 of window 1
set pageLabelText to value of static text 2 of splitter group 1 of window 1
end tell
end try
try --Set pageNo
set AppleScript's text item delimiters to {" of "}
set pageNo to pageNoText's first text item
end try
try --Only try setting pageLabel if the value may make sense
if (pageLabelText starts with "Back to ") or (pageLabelText starts with "Go to") or (pageLabelText = "") or (pageLabelText is missing value) then error
set pageLabel to pageLabelText
on error
set pageLabel to pageNo
end try
return {pageNo, pageLabel}
end getPageDetails
on getAddress()
set urlBuilder to NSURLComponents's new's initWithString:getPDFExpertFileURL()
set {urlBuilder's |scheme|, urlBuilder's |host|} to {"pdfexpert", ""}
set title to getPDFExpertName()
set {pageNo, pageLabel} to getPageDetails()
if pageNo is not missing value then
set title to title & " p. " & pageLabel
set urlBuilder's queryItems to {NSURLQueryItem's queryItemWithName:"p" value:pageNo}
--set urlBuilder's fragment to "page=" & pageNo --necessary for file:/ scheme
end if
return "[" & title & "](" & (urlBuilder's |string| as string) & ")"
end getAddress
getAddress()
Open Item
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property NSURLComponents : a reference to current application's NSURLComponents
property NSURLQueryItem : a reference to current application's NSURLQueryItem
property NSMutableDictionary : a reference to current application's NSMutableDictionary
property NSFileManager : a reference to current application's NSFileManager's defaultManager
property NSURL : a reference to current application's NSURL
on getPDFExpertName()
tell application "System Events" to return name of first window of process "PDF Expert"
end getPDFExpertName
on replaceText(this_text, search_string, replacement_string)
set str to current application's NSString's stringWithString:this_text
return (str's stringByReplacingOccurrencesOfString:search_string withString:replacement_string) as string
end replaceText
on cleanURL(fullURL)
--Clean up historic bad encodings
if fullURL contains "%2520" then
set fullURL to replaceText(fullURL, "%25", "%")
set fullURL to replaceText(fullURL, "%23", "#")
set fullURL to replaceText(fullURL, "(", "(")
set fullURL to replaceText(fullURL, ")", ")")
end if
set fullURL to replaceText(fullURL, ".pdf&", ".pdf?")
set urlObj to NSURLComponents's componentsWithString:fullURL
--Handle Hook file URLs by stripping the '/file:/' component from the start of the path
set AppleScript's text item delimiters to "file:/"
get (urlObj's |path| as string)'s text items
try
if (urlObj's |path| as string)'s second text item is not "" then set urlObj's |path| to (urlObj's |path| as string)'s second text item
end try
--Handle old-style paths (which appear with a leading / ...)
if ((urlObj's |path|) as string) contains ":Users:" then set urlObj's |path| to (POSIX path of (text 2 thru end of (urlObj's |path| as string)))
--Optional: search for files where there is no match
if not (NSFileManager's fileExistsAtPath:(urlObj's |path|)) then
set newObj to findItemURL(urlObj)
if newObj is not missing value then set urlObj's |path| to newObj's |path|
end if
return urlObj
end cleanURL
to findItemURL(urlObj)
set {urlObj's |scheme|, urlObj's |host|} to {"file", ""}
set filename to urlObj's |URL|'s lastPathComponent
set searchResults to do shell script "mdfind -name " & quoted form of (filename as string)
set searchResultURLs to {}
repeat with searchResult in paragraphs of searchResults
set end of searchResultURLs to (NSURL's fileURLWithPath:searchResult isDirectory:false relativeToURL:(urlObj's |URL|))
end repeat
set ourPathComponents to urlObj's |URL|'s pathComponents
set leadingCandidate to {_URL:missing value, penalty:999999}
repeat with searchResultURL in searchResultURLs
set diff to ((searchResultURL's pathComponents)'s differenceFromArray:ourPathComponents)
set penalty to (count of (diff's insertions)) + (count of (diff's removals))
if penalty < leadingCandidate's penalty then set leadingCandidate to {_URL:searchResultURL, penalty:penalty}
end repeat
return contents of leadingCandidate's _URL
end findItemURL
on getKvs(fromURLComponents)
if fromURLComponents's query() is missing value then
set fromURLComponents's query to fromURLComponents's fragment()
set fromURLComponents's fragment to ""
end if
set dict to NSMutableDictionary's new()
try
repeat with queryItem in fromURLComponents's queryItems
(dict's setValue:(queryItem's value as string) forKey:(queryItem's |name|))
end repeat
end try
return dict as record
end getKvs
on moveViewToPage(pageNo)
set enabledViewElements to missing value
tell application "PDF Expert" to activate
tell application "System Events"
tell application process "PDF Expert"
if role description of value of attribute "AXFocusedUIElement" is "text field" then --Search bar taking focus?
key code 53
end if
tell menu bar 1
set goToPage to menu item "Go to Page..." of menu "Go"
if goToPage's enabled is not true then
--Side bar taking focus?
set enabledViewElements to every UI element of menu "View" whose (value of attribute "AXMenuItemMarkChar" of it) is equal to "✓"
keystroke "5" using {command down, option down} --faster than click UI element "No Left Panel" of menu "View"
end if
click goToPage
delay 0.05
keystroke pageNo
keystroke return
--Restore side bar if necessary
if enabledViewElements is not missing value then
repeat with element in enabledViewElements
if element's name is in {"Bookmarks", "Outline", "Annotation Summary", "Thumbnails Panel"} then
click element
exit repeat
end if
end repeat
end if
end tell
end tell
end tell
end moveViewToPage
on openItem(fullURL)
set urlObj to cleanURL(fullURL)
--Test if file exists
if not (NSFileManager's fileExistsAtPath:(urlObj's |path|)) then
display dialog "Unable to find file for URL " & fullURL & " looking at path " & urlObj's |path| with title "Hook PDF Expert Integration" buttons {"OK"} default button 1 cancel button 1 giving up after 2
return urlObj's |path|
end if
--Convert URL to file URL
set {urlObj's |scheme|, urlObj's |host|} to {"file", ""}
set furl to urlObj's |URL| as «class furl»
tell application "PDF Expert" to open location furl
-- Get page number
set pageRefs to getKvs(urlObj) & {p:missing value, page:missing value} --Neuberg p. 241
if pageRefs's p is missing value then set pageRefs's p to pageRefs's page
set p to pageRefs's p
if p is missing value then return
--display dialog "Go to page " & p giving up after 1
-- Get file name
tell application "Finder" to set pdfName to displayed name of (info for furl)
set AppleScript's text item delimiters to ".pdf"
set pdfName to pdfName's first text item
-- Move to page
set counter to 30
repeat while counter is greater than 0
if getPDFExpertName() contains pdfName then
moveViewToPage(p)
return
else
delay 0.1
end if
set counter to counter - 1
end repeat
end openItem
openItem("$0")
Thank you for the script!
I can’t seem to get it to work, can I ask what URL scheme you are using now? Thanks!
Hi Steve, sorry to bother you, but is this script still working? I copied it into the hook but I always get “No item or link” feedback, I would like to know if you could help me. Thank you very much! (PS, What is the url scheme you entered? )
Oh no, do not work again. Thanks anyway man.
Did I miss any step? Is copying & pasting all I need to do ?
For linking to entire PDFs (rather than deep linking): If you can manually get a link to the PDF in PDFExpert, then you could use the Focus on Link in Clipboard
command in the clipboard to set Hook’s title bar to this document. From that point on you could hook items to the document.
I modified lawyerboy’s Get Address script so Hook can use his Open Item script.
But the bad thing about the change is the page number can’t be appended to the file name.
If you find the script is not working for you, e.g., you get No linkable item found error, you can change the number at line 23 of Get Address script, increase it by 0.1 each time and see it solves the problem:
line 23: delay 0.3
Get Address
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property NSURLComponents : a reference to current application's NSURLComponents
property NSURLQueryItem : a reference to current application's NSURLQueryItem
property NSMutableDictionary : a reference to current application's NSMutableDictionary
property NSFileManager : a reference to current application's NSFileManager's defaultManager
property NSURL : a reference to current application's NSURL
--Get Address
on getPDFExpertFileURL()
local fileURL
set fileURL to missing value
tell application "System Events"
activate application "PDF Expert"
tell process "PDF Expert" to set showInFinder to menu item "Show in Finder" of menu 1 of menu bar item "File" of menu bar 1
set isEnabled to showInFinder's enabled
end tell
if isEnabled then
tell application "System Events" to tell process "PDF Expert" to click showInFinder
delay 0.3
tell application "Finder"
set openWindows to id of every window
set fileURL to URL of (selection as alias)
close (get (every window whose id of it is not in openWindows))
end tell
end if
tell application "System Events" to activate application "PDF Expert"
return fileURL
end getPDFExpertFileURL
on getPDFExpertName()
tell application "System Events" to return name of first window of process "PDF Expert"
end getPDFExpertName
on getPageDetails()
set {pageNo, pageLabel} to {missing value, missing value}
try --Get the details we need
tell application "System Events" to tell process "PDF Expert"
set pageNoText to value of static text 1 of splitter group 1 of window 1
set pageLabelText to value of static text 2 of splitter group 1 of window 1
end tell
end try
try --Set pageNo
set AppleScript's text item delimiters to {" of "}
set pageNo to pageNoText's first text item
end try
try --Only try setting pageLabel if the value may make sense
if (pageLabelText starts with "Back to ") or (pageLabelText starts with "Go to") or (pageLabelText = "") or (pageLabelText is missing value) then error
set pageLabel to pageLabelText
on error
set pageLabel to pageNo
end try
return {pageNo, pageLabel}
end getPageDetails
on getAddress()
set urlBuilder to NSURLComponents's new's initWithString:getPDFExpertFileURL()
set {urlBuilder's |scheme|, urlBuilder's |host|} to {"file", ""}
set title to getPDFExpertName()
set {pageNo, pageLabel} to getPageDetails()
if pageNo is not missing value then
set title to title & " p. " & pageLabel
set urlBuilder's queryItems to {NSURLQueryItem's queryItemWithName:"p" value:pageNo}
--set urlBuilder's fragment to "page=" & pageNo --necessary for file:/ scheme
end if
return "[" & title & "](" & (urlBuilder's |string| as string) & "#p=" & pageNo & ")"
end getAddress
getAddress()
Open Item
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property NSURLComponents : a reference to current application's NSURLComponents
property NSURLQueryItem : a reference to current application's NSURLQueryItem
property NSMutableDictionary : a reference to current application's NSMutableDictionary
property NSFileManager : a reference to current application's NSFileManager's defaultManager
property NSURL : a reference to current application's NSURL
on getPDFExpertName()
tell application "System Events" to return name of first window of process "PDF Expert"
end getPDFExpertName
on replaceText(this_text, search_string, replacement_string)
set str to current application's NSString's stringWithString:this_text
return (str's stringByReplacingOccurrencesOfString:search_string withString:replacement_string) as string
end replaceText
on cleanURL(fullURL)
--Clean up historic bad encodings
if fullURL contains "%2520" then
set fullURL to replaceText(fullURL, "%25", "%")
set fullURL to replaceText(fullURL, "%23", "#")
set fullURL to replaceText(fullURL, "(", "(")
set fullURL to replaceText(fullURL, ")", ")")
end if
set fullURL to replaceText(fullURL, ".pdf&", ".pdf?")
set urlObj to NSURLComponents's componentsWithString:fullURL
--Handle Hook file URLs by stripping the '/file:/' component from the start of the path
set AppleScript's text item delimiters to "file:/"
get (urlObj's |path| as string)'s text items
try
if (urlObj's |path| as string)'s second text item is not "" then set urlObj's |path| to (urlObj's |path| as string)'s second text item
end try
--Handle old-style paths (which appear with a leading / ...)
if ((urlObj's |path|) as string) contains ":Users:" then set urlObj's |path| to (POSIX path of (text 2 thru end of (urlObj's |path| as string)))
--Optional: search for files where there is no match
if not (NSFileManager's fileExistsAtPath:(urlObj's |path|)) then
set newObj to findItemURL(urlObj)
if newObj is not missing value then set urlObj's |path| to newObj's |path|
end if
return urlObj
end cleanURL
to findItemURL(urlObj)
set {urlObj's |scheme|, urlObj's |host|} to {"file", ""}
set filename to urlObj's |URL|'s lastPathComponent
set searchResults to do shell script "mdfind -name " & quoted form of (filename as string)
set searchResultURLs to {}
repeat with searchResult in paragraphs of searchResults
set end of searchResultURLs to (NSURL's fileURLWithPath:searchResult isDirectory:false relativeToURL:(urlObj's |URL|))
end repeat
set ourPathComponents to urlObj's |URL|'s pathComponents
set leadingCandidate to {_URL:missing value, penalty:999999}
repeat with searchResultURL in searchResultURLs
set diff to ((searchResultURL's pathComponents)'s differenceFromArray:ourPathComponents)
set penalty to (count of (diff's insertions)) + (count of (diff's removals))
if penalty < leadingCandidate's penalty then set leadingCandidate to {_URL:searchResultURL, penalty:penalty}
end repeat
return contents of leadingCandidate's _URL
end findItemURL
on getKvs(fromURLComponents)
if fromURLComponents's query() is missing value then
set fromURLComponents's query to fromURLComponents's fragment()
set fromURLComponents's fragment to ""
end if
set dict to NSMutableDictionary's new()
try
repeat with queryItem in fromURLComponents's queryItems
(dict's setValue:(queryItem's value as string) forKey:(queryItem's |name|))
end repeat
end try
return dict as record
end getKvs
on moveViewToPage(pageNo)
set enabledViewElements to missing value
tell application "PDF Expert" to activate
tell application "System Events"
tell application process "PDF Expert"
if role description of value of attribute "AXFocusedUIElement" is "text field" then --Search bar taking focus?
key code 53
end if
tell menu bar 1
set goToPage to menu item "Go to Page..." of menu "Go"
if goToPage's enabled is not true then
--Side bar taking focus?
set enabledViewElements to every UI element of menu "View" whose (value of attribute "AXMenuItemMarkChar" of it) is equal to "✓"
keystroke "5" using {command down, option down} --faster than click UI element "No Left Panel" of menu "View"
end if
click goToPage
delay 0.05
keystroke pageNo
keystroke return
--Restore side bar if necessary
if enabledViewElements is not missing value then
repeat with element in enabledViewElements
if element's name is in {"Bookmarks", "Outline", "Annotation Summary", "Thumbnails Panel"} then
click element
exit repeat
end if
end repeat
end if
end tell
end tell
end tell
end moveViewToPage
on openItem(fullURL)
set urlObj to cleanURL(fullURL)
--Test if file exists
if not (NSFileManager's fileExistsAtPath:(urlObj's |path|)) then
display dialog "Unable to find file for URL " & fullURL & " looking at path " & urlObj's |path| with title "Hook PDF Expert Integration" buttons {"OK"} default button 1 cancel button 1 giving up after 2
return urlObj's |path|
end if
--Convert URL to file URL
set {urlObj's |scheme|, urlObj's |host|} to {"file", ""}
set furl to urlObj's |URL| as «class furl»
tell application "PDF Expert" to open location furl
-- Get page number
set pageRefs to getKvs(urlObj) & {p:missing value, page:missing value} --Neuberg p. 241
if pageRefs's p is missing value then set pageRefs's p to pageRefs's page
set p to pageRefs's p
if p is missing value then return
--display dialog "Go to page " & p giving up after 1
-- Get file name
tell application "Finder" to set pdfName to displayed name of (info for furl)
set AppleScript's text item delimiters to ".pdf"
set pdfName to pdfName's first text item
-- Move to page
set counter to 30
repeat while counter is greater than 0
if getPDFExpertName() contains pdfName then
moveViewToPage(p)
return
else
delay 0.1
end if
set counter to counter - 1
end repeat
end openItem
openItem("$0")
It works great!
Thank you so much. God bless you.
If i open Hook(⌃ + H) on the ‘PDF Expert’ , the ‘Finder’ shows up together, can i prevent it?
The process may be running behind the scenes, but don’t want the window to pop up.
In this question, It’s just about copy specific pdf page markdown link to paste it.
I’d greatly appreciate any help you can offer.
PDF Expert lacks automation for linking. It does a linkable app in the sense defined by Mac developers here: Manifesto for Ubiquitous Linking. The script above uses a work-around involving the Finder. It is a problem with Readdle, you could ask them to take a few minutes to implement an API for linking: Contacting Developers of Other Apps and Information for Developers; it normally takes a dev less than a day to do it. Or you could choose from their competitors that are linkable (there are several to choose from).
It is very kind of you to make an e-mail form. Thank you. I’ll send an email right away.
I have contacted Readdle with the request letter template and links, as I’m sure many others have done. I received a not so encouraging reply. It would be nice if those who have implemented an API would offer a discount for switching!