Adding keyboard shortcuts to Viaplay
Now that the NHL playoff season has finally arrived, I've found myself watching a lot of hockey through Viaplay streaming service. When watching those games on my laptop, I noticed that I would instinctually reach for m
or f
key to toggle mute or fullscreen respectively. And I would be disappointed time and time again to notice that it wouldn't work.
I decided to fix that.
In May, Brian Lagunas asked on Twitter, why people decided to do web development out of all the possible sub-genres of software development. My original answer discussed the distribution but another major reason why I've become so fond of web as a platform is the extensibility. I can write Javascript to modify pretty much anything that's happening on the screen and so I can create the tooling I need for myself even if the original developer didn't provide those.
The process of exploration
Before starting a new project to build a Chrome Extension, I started from the developer console to see what kind of things I'd be able to do with Javascript to modify the behavior of the app. I figured I could trigger 'click' events to simulate a human clicking on the mute or fullscreen button.
document.querySelector(".audio-control").click();
This worked but only if the user had moved their mouse to reveal the control panel as those items would be removed from the DOM when not being hovered.
const showUI = () => {
document
.querySelector(".scene")
.dispatchEvent(new Event("mousemove", { bubbles: true }));
};
I built a function that triggers a mousemove
event and bubbles that up in the DOM to make sure it reaches the correct layer where the control panel will become visible.
document.addEventListener("keyup", (event) => {
/* If it's m, we want to mute/unmute */
if (event.key === "m") {
showUI();
document.querySelector(".audio-control").click();
}
})
With these two pieces, I was able to build the first version of the functionality. Listening to keyup
event and in case of 'm'
being pushed, we show the UI and click on the mute button.
The problem of clicking
My code kinda worked but not really. If you have ever used Viaplay, you know that it will cause the video to pause if clicked anywhere outside those buttons. I tried all sorts of things to figure out how it was deciding that functionality but no matter what I tried, it would always pause the video (in addition to correctly applying mute).
That was bit annoying but I figured that since I was just building it for myself, it was okay for now and started using it. But it wasn't okay, it became very annoying.
While I was watching the almost record-long playoffs game between Lightning and Blue Jackets last night, a revelation hit me: I could just first pause the game and then quickly hit the action I wanted and maybe it could be made smooth enough.
if (event.key === "m") {
document.querySelector(".scene").click();
setTimeout(() => {
showUI();
const muteButton = document.querySelector(".audio-control");
muteButton.click();
}, 20);
}
So I added a click
to pause the video and then run the previous code with a setTimeout
of 20ms. For a reason that I don't know yet, fullscreen works fine with a 10ms delay but mute needed some extra time to be available so I put that into 20ms.
To my surprise, it works brilliantly. I can't even notice the pause.
I then added fullscreen functionality:
if (event.key === "f") {
document.querySelector(".scene").click();
setTimeout(() => {
showUI();
const fullscreen = document.querySelector(".fullscreen");
if (fullscreen) {
fullscreen.click();
} else {
document.querySelector(".no-fullscreen").click();
}
}, 10);
}
which needed to be a bit more involved because unlike the mute functionality, this one changes classes when toggled.
The code
Since the project is still in testing and might require some tweaking, I haven't packaged and published it as a Chrome Extension yet. However, all the code is available in GitHub at hamatti/viaplay-keyboard-shortcuts and you can install it as an unpacked extension through the extension panel by downloading the code from GitHub and using Load unpacked function.
The code is MIT licensed so it's open source and you can modify and extend it as you wish.
Thanks to Futurice's Spice Program for supporting the creation of this software.