Files
com.xaymar.www/assets/site.js
T
Michael Fabian 'Xaymar' Dirks 8b2b0e03bc media: Fix volume keybinds
2022-11-27 07:28:24 +01:00

435 lines
13 KiB
JavaScript

'use strict';
import("./HTMLMediaElement.mjs");
async function xmr_media_lazyload_perform(element) {
let content = element.querySelector("noscript");
if (content) {
element.innerHTML = content.innerText;
}
}
async function xmr_media_lazyload_initialize() {
// Figure out what to load.
let elements = document.querySelectorAll(".block-media > [data-lazyload]");
let stack = Array.from(elements);
console.debug("Lazily loading " + stack.length + " elements...");
// Add a lazyloading handler to all entries.
for (let el of stack) {
xmr_media_lazyload_perform(el);
}
}
async function xmr_initialize_player(el) {
let media = el.querySelector("video");
if (!media)
el.querySelector("audio");
let play_pause = el.querySelector(".play");
{ // Play/Pause
play_pause.update = function() {
if (media.paused) {
play_pause.classList.remove("playing");
play_pause.dataset.symbol = "⏵";
play_pause.ariaLabel = "Play";
} else if (media.error || media.ended) {
play_pause.classList.remove("playing");
play_pause.dataset.symbol = "⏹";
play_pause.ariaLabel = "Stopped";
} else {
play_pause.classList.add("playing");
play_pause.dataset.symbol = "⏸";
play_pause.ariaLabel = "Pause";
}
play_pause.innerText = play_pause.dataset.symbol;
}
play_pause.addEventListener("click", () => {
if (media.paused) {
media.play();
} else {
media.pause();
}
});
play_pause.addEventListener("keydown", (ev) => {
if (ev.isComposing || ev.keyCode === 229) {
// Ignore IME compositing.
return;
}
if (["Space", "Enter"].includes(ev.code)) {
play_pause.click();
ev.preventDefault();
ev.stopPropagation();
}
});
media.addEventListener("play", () => { play_pause.update(); });
media.addEventListener("pause", () => { play_pause.update(); });
media.addEventListener("ended", () => { play_pause.update(); });
media.addEventListener("error", () => { play_pause.update(); });
play_pause.update();
}
let playback_time = el.querySelector(".time");
{ // Time
playback_time.update = function() {
function formatSeconds(seconds, with_ms, with_minutes, with_hour) {
let result = [];
if (isFinite(seconds) && !isNaN(seconds)) {
let tainted_seconds = seconds % 60;
let pure_seconds = Math.floor(seconds % 60);
let tainted_minutes = ((seconds - pure_seconds) / 60);
let pure_minutes = Math.floor(tainted_minutes % 60);
let pure_hours = Math.floor((tainted_minutes - pure_minutes) / 60);
result.unshift(`${pure_seconds.toString(10).padStart(2, '0')}`);
if (with_ms) {
result[0] = `${result[0]}.${Math.floor((tainted_seconds % 1) * 100).toString(10).padStart(2, '0')}`
}
if ((with_minutes === true) || ((with_minutes === undefined) && (pure_minutes > 0))) {
result[0] = result[0].padStart(2, '0');
result.unshift(`${pure_minutes.toString(10)}`);
}
if ((with_hour === true) || ((with_hour === undefined) && (pure_hours > 0))) {
result[0] = result[0].padStart(2, '0');
result.unshift(`${pure_hours.toString(10)}`);
}
}
return result;
}
let duration = formatSeconds(media.duration, true);
let current = formatSeconds(media.currentTime, true, duration.length >= 2, duration.length >= 3);
for (let idx in duration) {
current[idx].padStart(duration[idx].length, '0');
}
if (duration.length > 0) {
playback_time.innerText = `${current.join(':')} / ${duration.join(':')}`;
} else {
playback_time.innerText = `${current.join(':')}`;
}
}
media.addEventListener("timeupdate", () => { playback_time.update(); });
media.addEventListener("durationupdate", () => { playback_progress.update(); });
media.addEventListener("loadedmetadata", () => { playback_time.update(); });
playback_time.update();
}
let playback_progress = el.querySelector(".progress");
{ // Progress
playback_progress.update = function() {
playback_progress.disabled = !media.seekable;
playback_progress.min = 0;
playback_progress.max = media.duration * 100;
playback_progress.value = media.currentTime * 100;
}
playback_progress.addEventListener("input", () => {
if (isFinite(media.duration)) {
media.currentTime = parseInt(playback_progress.value, 10) / 100;
}
});
media.addEventListener("timeupdate", () => { playback_progress.update(); });
media.addEventListener("durationupdate", () => { playback_progress.update(); });
media.addEventListener("loadeddata", () => { playback_progress.update(); });
media.addEventListener("loadedmetadata", () => { playback_progress.update(); });
playback_progress.update();
}
let audio_mute = el.querySelector(".mute");
{ // Mute
audio_mute.update = function() {
if (media.muted) {
audio_mute.classList.add("muted");
audio_mute.dataset.symbol = "🔇";
audio_mute.ariaLabel = "Unmute";
} else {
audio_mute.classList.remove("muted");
if (media.volume > 0.5) {
audio_mute.dataset.symbol = "🔊";
} else if (media.volume > 0.25) {
audio_mute.dataset.symbol = "🔉";
} else {
audio_mute.dataset.symbol = "🔈";
}
audio_mute.ariaLabel = `Volume: ${(media.volume * 100).toString(10)}%`;
}
audio_mute.innerText = audio_mute.dataset.symbol;
}
audio_mute.addEventListener("click", () => {
media.muted = !media.muted;
});
audio_mute.addEventListener("keydown", (ev) => {
if (ev.isComposing || ev.keyCode === 229) {
// Ignore IME compositing.
return;
}
if (["Space", "Enter"].includes(ev.code)) {
audio_mute.click();
ev.preventDefault();
ev.stopPropagation();
}
});
media.addEventListener("volumechange", () => {
audio_mute.update();
});
audio_mute.update();
}
let audio_volume = el.querySelector(".volume");
{ // Volume
audio_volume.min = 0;
audio_volume.max = 2147483647;
audio_volume.update = function() {
let min = parseInt(audio_volume.min, 10);
let max = parseInt(audio_volume.max, 10);
let dlt = max - min;
audio_volume.value = (media.logVolume * dlt) + min;
audio_volume.ariaLabel = `Volume: ${(media.volume * 100).toString(10)}%`;
if (media.muted) {
audio_volume.classList.add("muted");
} else {
audio_volume.classList.remove("muted");
}
}
audio_volume.addEventListener("input", () => {
let min = parseInt(audio_volume.min, 10);
let max = parseInt(audio_volume.max, 10);
let val = parseInt(audio_volume.value, 10);
let dlt = max - min;
let vol = (val + min) / dlt;
media.logVolume = vol;
media.muted = (media.volume < 0.01);
});
media.addEventListener("volumechange", () => { audio_volume.update(); });
audio_volume.update();
}
let fullscreen = el.querySelector(".fullscreen");
{ // Fullscreen
fullscreen.update = function() {
if (document.fullscreenElement) {
fullscreen.dataset.symbol = "\u200F⛶";
} else {
fullscreen.dataset.symbol = "⛶";
}
fullscreen.innerText = fullscreen.dataset.symbol;
};
fullscreen.addEventListener("click", () => {
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
el.requestFullscreen();
}
});
fullscreen.addEventListener("keydown", (ev) => {
if (ev.isComposing || ev.keyCode === 229) {
// Ignore IME compositing.
return;
}
if (["Space", "Enter"].includes(ev.code)) {
fullscreen.click();
ev.preventDefault();
}
})
el.addEventListener("fullscreenchange", () => {
fullscreen.update();
});
fullscreen.update();
}
let variant = el.querySelector(".variant");
{ // Variants
variant.update = function() {
// Store current state and pause.
let paused = media.paused;
let muted = media.muted;
let volume = media.volume;
let time = media.currentTime;
media.pause();
play_pause.update();
// Tell the media source to begin loading.
media.src = variant.value;
media.load();
media.currentTime = time;
media.addEventListener("canplay", () => {
media.currentTime = time;
media.volume = volume;
media.muted = muted;
if (paused) {
media.pause();
} else {
media.play();
}
play_pause.update();
}, {
"once": true
})
}
variant.addEventListener("input", () => { variant.update(); });
variant.addEventListener("value", () => { variant.update(); });
// Variants - Add options from available sources.
let sources = el.querySelectorAll("source");
for (let k of sources) {
let option = document.createElement("option");
option.value = k.src;
option.textContent = k.title;
variant.appendChild(option);
}
variant.value = media.currentSrc;
}
{ // Keyboard/Mouse Controls
el.addEventListener("keydown", (ev) => {
if (ev.isComposing || ev.keyCode === 229) {
// Ignore IME compositing.
return;
}
if (["f", "F"].includes(ev.key)) {
fullscreen.click();
ev.preventDefault();
ev.stopPropagation();
} else if (["m", "M"].includes(ev.key)) {
audio_mute.click();
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "Space") {
play_pause.click();
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "Home") {
media.currentTime = 0;
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "ArrowLeft") {
media.currentTime -= 5;
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "Comma") {
media.currentTime -= .1;
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "Period") {
media.currentTime += .1;
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "ArrowRight") {
media.currentTime += 5;
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "End") {
media.currentTime = media.duration;
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "ArrowUp") {
media.logVolume = Math.max(0, Math.min(media.logVolume + 0.05, 1.0));
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "ArrowDown") {
media.logVolume = Math.max(0, Math.min(media.logVolume - 0.05, 1.0));
ev.preventDefault();
ev.stopPropagation();
} else if (["p", "P"].includes(ev.key)) {
media.preservesPitch = !media.preservesPitch;
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "PageDown") {
media.playbackRate = Math.max(0.25, Math.min(media.playbackRate - 0.05, 4.0));
ev.preventDefault();
ev.stopPropagation();
} else if (ev.code === "PageUp") {
media.playbackRate = Math.max(0.25, Math.min(media.playbackRate + 0.05, 4.0));
ev.preventDefault();
ev.stopPropagation();
} else if (["r", "R"].includes(ev.key)) {
media.playbackRate = 1.0;
ev.preventDefault();
ev.stopPropagation();
}
});
media.addEventListener("click", () => {
play_pause.click();
});
media.addEventListener("dblclick", () => {
fullscreen.click();
})
}
{ // Hide/Show controls
el.showOverlay = function() {
el.cancelHideOverlay();
el.classList.remove("hide");
}
el.hideOverlay = function() {
if (!media.paused && !media.ended && !media.error) {
el.classList.add("hide");
}
}
el.delayHideOverlay = function() {
el.cancelHideOverlay();
el.timer = setTimeout(() => { el.hideOverlay(); }, 2500);
}
el.cancelHideOverlay = function() {
if (el.timer) {
clearTimeout(el.timer);
}
}
el.addEventListener("mousemove", () => {
el.showOverlay();
if (!media.paused && !media.ended && !media.error) {
el.delayHideOverlay();
}
});
el.hideOverlay();
}
{ // Show/Hide Audio controls without audio.
function checkAudioPresence() {
let hasAudio = Boolean(media.mozHasAudio)
|| Boolean(media.webkitAudioDecodedByteCount)
|| Boolean(media.audioTracks && media.audioTracks.length);
audio_mute.style.display = hasAudio ? "" : "none";
audio_volume.style.display = hasAudio ? "" : "none";
}
media.addEventListener("loadedmetadata", () => { checkAudioPresence() });
media.addEventListener("loadeddata", () => { checkAudioPresence() });
checkAudioPresence();
}
// Signal the browser to try and load some information.
media.load();
}
async function xmr_initialize_players() {
// Figure out what to initialize.
let elements = document.querySelectorAll(".block-media.player");
let stack = Array.from(elements);
console.debug("Initializing " + stack.length + " players...");
// Add a lazyloading handler to all entries.
for (let el of stack) {
xmr_initialize_player(el);
}
}
(function() {
'use strict';
// Support for Mobile Devices
document.querySelector("#navigation-toggle").addEventListener("click", (ev) => {
document.querySelector("#header #navigation").classList.toggle("open");
});
// Lazily load Media
xmr_media_lazyload_initialize();
// Initialize media player.
xmr_initialize_players();
})();