JGC
JGC

Reputation: 602

Getting active browser window details in AppleScript

Aim: identify most recent browser window in macOS, and get the URL and title of its active tab as a Markdown link.

It's destined for an Alfred workflow triggered from other apps, but for now I'm just debugging the core of it in the Script Editor. I have both Safari and Chrome open, along with a number of other apps. From debugging I see it correctly lists all the open windows, but it never matches either of the if conditions. As further evidence, if I just use the tell application lines in isolation, the right results are returned. I'm sure this is dead simple.

set output to ""
tell application "System Events"
    set appNames to name of every application process whose visible is true
    repeat with appName in appNames
        if (appName = "Google Chrome") then
            using terms from application "Google Chrome"
                tell application appName to set currentTabTitle to title of active tab of front window
                tell application appName to set currentTabUrl to URL of active tab of front window
            end using terms from
            set output to "[" & currentTabTitle & "](" & currentTabUrl & ")"
            exit repeat
        else if (appName = "Safari") then
            using terms from application "Safari"
                tell application appName to set currentTabTitle to name of front document
                tell application appName to set currentTabUrl to URL of front document
            end using terms from
            set output to "[" & currentTabTitle & "](" & currentTabUrl & ")"
            exit repeat
        end if
    end repeat
end tell
return output

Upvotes: 0

Views: 1632

Answers (1)

CJK
CJK

Reputation: 6102

As discussed in the comments, the assumption your script makes is that AppleScript will return a list of processes ordered by the application which most recently had focus, but this isn't the case.

However, you can retrieve a list of application names in this order using a shell command lsappinfo metainfo. Piping this through a few additional commands to isolate the information of interest and clean up the text:

lsappinfo metainfo \
    | grep bringForwardOrder \
    | grep -E -o '"[^"]+"' \
    | tr -d "\""

produces a nice, readable, ordered list of applications, where each item in the last was last active more recently than the one below it:

Google Chrome
Script Editor
Atom
Messages
WhatsApp
Finder
Safari
Script Debugger
WebTorrent

Testing this, when I switch to Script Editor, and then run the shell command again, the list returned is:

Script Editor
Google Chrome
Atom
Messages
WhatsApp
Finder
Safari
Script Debugger
WebTorrent

Since you're only interested in discerning this order between two specific applications, namely Safari and Google Chrome, the shell command can be simplified somewhat to:

lsappinfo metainfo | grep -E -o 'Safari|Google Chrome' | head -1

which will return a single name, that being the browser that is either currently active or most recently had focus; or an empty string if, say, neither browser is running.

Incorporating this into your AppleScript, and cleaning the script up somewhat:

property nil : ""

set [currentTabTitle, currentTabUrl] to [nil, nil]

set cmd to "lsappinfo metainfo | grep -E -o 'Safari|Google Chrome' | head -1"
set frontmostBrowser to do shell script cmd

if the frontmostBrowser = "" then return nil

if the frontmostBrowser = "Google Chrome" then

    tell application "Google Chrome" to tell ¬
        (a reference to the front window) to tell ¬
        (a reference to its active tab)

        if not (it exists) then return nil
        set currentTabTitle to its title
        set currentTabUrl to its URL
    end tell

else if the frontmostBrowser = "Safari" then

    tell application "Safari" to tell ¬
        (a reference to the front document)

        if not (it exists) then return nil
        set currentTabTitle to its name
        set currentTabUrl to its URL
    end tell

end if

return "[" & currentTabTitle & "](" & currentTabUrl & ")"

However, I would suggest actually composing the script as a shell script. I believe a shell script will be faster than an AppleScript, because the AppleScript will take more time to spawn a shell process and run a shell script than the shell would take to compile and run an AppleScript (in this instance—although, generally, osascript is typically slower than a native AppleScript process). The other benefit is that, with the use of shell variable substitutions, we can make the resulting script a lot more compact, condensing the two browser AppleScript code blocks into a single, dual-purpose text script that osascript will compile once the variable substitutions have been made (thus avoiding the runtime/compile-time malarky I mentioned in the comments).

The shell (bash) script looks like this:

browser=$(lsappinfo metainfo | grep -E -o 'Safari|Google Chrome' | head -1)
[[ "$browser" = "Safari" ]] && syntax="current" || syntax="active"

script="tell app \"$browser\" to tell ¬
        (a reference to the front window) to tell ¬
        (a reference to its $syntax tab)

        if not (it exists) then return \"\"
        \"[\" & its name & \"](\" & its URL & \")\"
end tell"

[[ -n "$browser" ]] && osascript <<< "$script" || echo ""

Upvotes: 6

Related Questions