Custom commands in Firefox with Tridactyl
2026-02-20
The scenario
You're on a web page and you want to extract some content from it and use it in an external command. Or a more specific use case, you use Miniflux as your feed reader to follow some podcasts and you want to play those podcasts in MPD. You use Firefox as your browser together with Tridactyl and Native Messaging. mpc will be used for controlling MPD.
The solution
The audio part for a podcast is rendered as an <audio> element in Miniflux.
An <audio> element looks something like this:
<audio ...>
<source src="https://example.com/sound.mp3" ...>
</audio>
So to get the URL to the audio file, we select the src attribute of the
<source> element. For our use case, we know that we'll only have one of these
elements, so we're happy with just getting the first one:
js document.querySelector("source").src
The output is then piped to the
shellescape
method using the special variable JS_ARG, which contains the result from the
previous command (shown on two lines for clarity):
js document.querySelector("source").src |
js -p tri.excmds.shellescape(JS_ARG)
The -p flag is needed for JS_ARG to work.
Lastly, we call our external command with the escaped URL as an argument.
shellescape returns a promise, so we need to handle that. We also need to
prefix everything with
composite,
to make the pipe work. Combining everything and creating a new
command,
this is the final line that goes into our ~/.tridactylrc (or wherever you
keep it) file:
command pod2mpd composite js document.querySelector("source").src | js -p tri.excmds.shellescape(JS_ARG).then(url => tri.excmds.exclaim_quiet('mpc add ' + url))
Finally we bind a key sequence to the command:
bind ,p pod2mpd
Now, pressing ,p will find the first source element on the current page and
add its URL to MPD. This could, of course, be altered to instead send the link
to another media player, download the file, or call an external script for more
advanced handling (perhaps selecting multiple elements on the page, extracting
links and selecting among them using fzf),
and so on. Lots of possibilities!