Universal media seek controls on macOS with Hammerspoon
I switch between Spotify, Apple Music, and YouTube in Chrome depending on what I'm doing. The problem is that each app has its own keyboard shortcuts for seeking, and none of them work when the app isn't focused. I wanted one hotkey to rewind 10 seconds and another to fast-forward 10 seconds, regardless of which player is running.
Hammerspoon makes this pretty straightforward.
local music_mod = {"cmd", "alt", "ctrl"}
-- Seek the actively playing YouTube tab across all Chrome windows
local function youtubeSeek(offset)
hs.osascript.applescript(string.format([[
tell application "Google Chrome"
repeat with w in windows
repeat with t in tabs of w
if URL of t contains "youtube.com/watch" then
set isPaused to execute t javascript "document.querySelector('video').paused"
if isPaused is "false" then
set pos to execute t javascript "document.querySelector('video').currentTime"
execute t javascript "document.querySelector('video').currentTime = " & (pos + %f)
return
end if
end if
end repeat
end repeat
end tell
]], offset))
end
local function mediaSeek(offset)
local spotify = hs.application.get("Spotify")
if spotify and spotify:isRunning() and hs.spotify.getPlaybackState() == hs.spotify.state_playing then
hs.spotify.setPosition(hs.spotify.getPosition() + offset)
return
end
local music = hs.application.get("Music")
if music and music:isRunning() and hs.itunes.getPlaybackState() == hs.itunes.state_playing then
hs.itunes.setPosition(hs.itunes.getPosition() + offset)
return
end
local chrome = hs.application.get("Google Chrome")
if chrome and chrome:isRunning() then
youtubeSeek(offset)
end
end
hs.hotkey.bind(music_mod, "left", function()
mediaSeek(-10)
end)
hs.hotkey.bind(music_mod, "right", function()
mediaSeek(10)
end)
| Shortcut | Action |
|---|---|
Cmd + Alt + Ctrl + Left | Rewind 10 seconds |
Cmd + Alt + Ctrl + Right | Fast-forward 10 seconds |
How it picks the player
The mediaSeek function checks which app is actively playing, not just which app is running:
- Spotify - checks
getPlaybackState()againststate_playingto confirm Spotify is actively playing, not just open. - Apple Music - same check via
hs.itunes(Hammerspoon still uses the old iTunes module name). - YouTube in Chrome - if neither desktop player is active, it scans all Chrome windows and tabs for a
youtube.com/watchpage wherevideo.pausedisfalse. If you have multiple YouTube tabs open, only the one that's actually playing gets seeked.
First active player wins. If nothing is playing, the hotkey does nothing.
Setup
- Install Hammerspoon if you haven't already.
- For YouTube control, enable JavaScript execution in Chrome: View > Developer > Allow JavaScript from Apple Events.
- Add the script to your
~/.hammerspoon/init.lua. - Reload the config with
Cmd + Alt + Ctrl + R(or click "Reload Config" from the Hammerspoon menu bar icon).
Tweaking
The offset is just a number in seconds, so you can change mediaSeek(-10) and mediaSeek(10) to whatever you want. You could also add separate bindings for smaller jumps:
hs.hotkey.bind({"cmd", "alt", "ctrl", "shift"}, "left", function()
mediaSeek(-5)
end)
hs.hotkey.bind({"cmd", "alt", "ctrl", "shift"}, "right", function()
mediaSeek(5)
end)