Last active
May 20, 2022 00:52
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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