Skip to content

Instantly share code, notes, and snippets.

@HT-7
Last active May 20, 2022 00:52
Show Gist options
  • Save HT-7/d6a044b662642fd3936d4a11a40a514b to your computer and use it in GitHub Desktop.
Save HT-7/d6a044b662642fd3936d4a11a40a514b to your computer and use it in GitHub Desktop.
Playback keyboard controls (jumping, skipping, volume, and speed) for web media players which lack such controls natively.
// Playback keyboard controls script
// (currently only works on dedicated media pages)
// Configuration
var jump_distance_forward = 10; // Jump this many seconds forward using right arrow key.
var jump_distance_backward = 5; // Jump this many seconds backward using left arrow key.
var speed_step = 1/4; // Speed increased or decreased by this value using arrow keys up and down.
var volume_step = 1/10; // Volume increased or decreased by this value using +-.
var volume_step_fine = 1/100; // Volume increased or decreased by this value if below volume_step.
// Seek: 0 to 9 Reset the speed using "Insert".
// media checker
var mediaType; // for compatibility
var playerExists = false; // is set to 1 below if player exists
var checkMediaType_enabled = true; // for debugging purposes
var media_hotkeys_enabled = true; // for debugging purposes
var media_element = {};
function checkMediaType() {
if ( checkMediaType_enabled == true ) {
// checks whether it is a video or an audio tag
var mediaTypeBeforeCheck = mediaType;
if (document.getElementsByTagName("video")[0]) { playerExists = true; mediaType = "video"; }
if (document.getElementsByTagName("audio")[0]) { playerExists = true; mediaType = "audio"; }
var mediaTypeAfterCheck = mediaType;
if (mediaTypeBeforeCheck != mediaTypeAfterCheck)
// Only show media type in console if it has changed.
console.log("Detected media type: " + mediaType);
media_element = document.getElementsByTagName(mediaType)[0];
// Set back to false if no player is found after using customMediaElement.
media_element ? playerExists=true : playerExists=false;
}
}
function customMediaElement(custom_media_element) {
checkMediaType_enabled = false;
if (custom_media_element) {
playerExists = true;
media_element = custom_media_element;
console.log("Custom media element set. Reset using checkMediaType_enabled=1.");
} else { console.error("No such media element found."); }
}
// Additional checks to ensure the player is detected
window.onclick = function() { checkMediaType(); };
window.addEventListener("keydown", function() { checkMediaType(); } );
// shortcuts for current time and duration
function getCurrentTime() { return Math.floor( media_element.currentTime ); }
function getDuration() { return Math.floor( media_element.duration ); }
function getVol() { return Math.round(media_element.volume*100 ); }
// Using Math.round for volume to prevent showing a number that is one below a multiple of volume_step in case of floating-point rounding errors, since volume can be adjusted in either direction.
// code deduplication
function jumpNum(num) {
media_element.currentTime=media_element.duration*0.1*num ;
console.log("Position: "+ 10*num +" % Time: " + getCurrentTime() + " / " + getDuration() + " s" );
}
function setVol(vol) {
media_element.volume = vol;
console.log("Volume: " + getVol() + " %" );
}
function incrVol(vol) {
media_element.volume += vol;
console.log("Volume: " + getVol() + " %" );
}
window.onkeydown = function(e) {
var key = e.keyCode ? e.keyCode : e.which;
if (playerExists && media_hotkeys_enabled) {
// Keys 0 to 9 of main row and NUM pad, and also "Home" and "End".
if (key == 48 || key == 96 || key == 36) jumpNum(0);
if (key == 49 || key == 97) jumpNum(1);
if (key == 50 || key == 98) jumpNum(2);
if (key == 51 || key == 99) jumpNum(3);
if (key == 52 || key == 100) jumpNum(4);
if (key == 53 || key == 101) jumpNum(5);
if (key == 54 || key == 102) jumpNum(6);
if (key == 55 || key == 103) jumpNum(7);
if (key == 56 || key == 104) jumpNum(8);
if (key == 57 || key == 105) jumpNum(9);
if (key == 35) jumpNum(10);
// Time skipping with left and right arrow keys.
if (key == 37) {
media_element.currentTime-=jump_distance_backward ;
console.log("Time: " + getCurrentTime() + " / " + getDuration() + " s" );
}
if (key == 39) {
media_element.currentTime+=jump_distance_forward ;
console.log("Time: " + getCurrentTime() + " / " + getDuration() + " s" );
}
// Speed control with up and down arrow keys, and reset with "Home" key.
if (key == 38) {
media_element.playbackRate+=speed_step ;
console.log("Speed: " + media_element.playbackRate);
}
if (key == 40 && media_element.playbackRate >= speed_step) {
// Preventing speed below 0 that would cause "DOMException: Operation is not supported".
media_element.playbackRate-=speed_step ;
console.log("Speed: " + media_element.playbackRate);
}
if (key == 45) {
// reset speed using "Insert" key
media_element.playbackRate=1;
console.log("Speed reset to 1.");
}
// Volume control (+ -)
if (key == 171 || key == 107) { // [+]
// set volume to 100% if closer to it than the value in volume_step to prevent errors
if (media_element.volume > (1-volume_step) ) {
setVol(1);
} else {
// increase volume by the value in volume_step if above volume_step, otherwise increase by volume_step_fine
media_element.volume < volume_step ? incrVol(volume_step_fine) : incrVol(volume_step);
}
}
if (key == 173 || key == 109) { // [-]
// Fine adjustment below volume_step. Check multiplied by 2 for last volume_step before phasing into volume_step_fine.
if (media_element.volume < volume_step*2) {
// If the volume is below volume_step, check if volume is greater than volume_step_fine. If not, set to 0.
media_element.volume > volume_step_fine ? incrVol(-volume_step_fine) : setVol(0);
} else {
// decrease volume by the value in volume_step
incrVol(-volume_step);
}
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment