Modernize player

This commit is contained in:
Michael Fabian 'Xaymar' Dirks
2023-04-05 22:07:03 +02:00
parent c9038087c5
commit e412170870
4 changed files with 270 additions and 103 deletions
+93 -49
View File
@@ -1,9 +1,9 @@
// --------------------------------------------------------------------------------
// Media Player
// --------------------------------------------------------------------------------
$media-player-button-size: 1.5rem;
player {
--button-size: 2.0rem;
overlay {
display: block;
width: 100%;
@@ -14,6 +14,48 @@ player {
background: transparent;
.variants {
position: absolute;
bottom: calc(var(--button-size) + 1.0rem);
right: calc(var(--button-size) + 1.0rem);
z-index: 2;
line-height: 1.1rem;
font-size: 1.1rem;
padding: 0.1em;
margin: 0;
max-height: 50%;
height: calc(10 * 1em);
appearance: none;
outline: none;
background: rgba(0, 0, 0, 0.9);
color: $theme-menu-color;
border: none;
transition: height ease-in-out 100ms, bottom ease-in-out 500ms, opacity ease-in-out 100ms;
option {
padding: 0.1em 0.25em;
margin: 0;
}
option:hover,
option:focus {
background: hsla($theme-hue, 75%, 30%, 0.5);
color: $theme-menu-color-active;
}
option:active {
background: hsla($theme-hue, 100%, 50%, 0.5);
color: $theme-menu-color-active;
}
}
.variants.hide {
height: 0px;
opacity: 0.0;
}
controls {
transition: bottom ease-in-out 100ms, opacity ease-in-out 100ms;
display: flex;
@@ -31,99 +73,95 @@ player {
left: 0;
right: 0;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 80%);
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.9) 0.5rem);
opacity: 1.0;
overflow: hidden;
user-select: none;
.play {
div {
display: block;
flex-grow: 0;
margin: 0;
padding: 0;
width: $media-player-button-size;
height: $media-player-button-size;
font-size: $media-player-button-size;
line-height: $media-player-button-size;
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
text-align: center;
user-select: none;
}
.time {
input {
display: block;
margin: 0;
padding: 0;
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
text-align: center;
user-select: none;
}
.play {
width: var(--button-size);
height: var(--button-size);
font-size: var(--button-size);
line-height: var(--button-size);
}
.time {
width: auto;
height: $media-player-button-size;
height: var(--button-size);
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
text-align: right;
line-height: $media-player-button-size;
line-height: var(--button-size);
user-select: auto;
}
.progress {
margin: 0;
padding: 0;
width: auto;
min-width: 5rem;
height: 100%;
height: var(--button-size);
flex-grow: 5;
flex-shrink: 1;
display: block;
user-select: none;
}
.mute {
display: block;
margin: 0;
padding: 0;
width: $media-player-button-size;
height: $media-player-button-size;
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
font-size: $media-player-button-size;
line-height: $media-player-button-size;
text-align: center;
user-select: none;
width: var(--button-size);
height: var(--button-size);
font-size: var(--button-size);
line-height: var(--button-size);
}
.volume {
display: block;
margin: 0;
padding: 0;
width: auto;
min-width: 3rem;
max-width: 6rem;
height: 100%;
height: var(--button-size);
flex-grow: 1;
flex-shrink: 5;
flex-basis: auto;
}
user-select: none;
.variant {
width: var(--button-size);
height: var(--button-size);
font-size: var(--button-size);
line-height: var(--button-size);
}
.fullscreen {
display: block;
margin: 0;
padding: 0;
width: $media-player-button-size;
height: $media-player-button-size;
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
font-size: $media-player-button-size;
line-height: $media-player-button-size;
text-align: center;
user-select: none;
width: var(--button-size);
height: var(--button-size);
font-size: var(--button-size);
line-height: var(--button-size);
}
}
}
@@ -133,6 +171,12 @@ player.hide {
cursor: none;
overlay {
.variants {
bottom: -100%;
opacity: 0.0;
transition: bottom ease-in-out 500ms, opacity ease-in-out 500ms;
}
controls {
bottom: -100%;
opacity: 0.0;
+108 -51
View File
@@ -24,14 +24,6 @@ async function xmr_media_lazyload_initialize() {
class XMediaPlayer {
constructor(element) {
this._media = element;
this._variants = new Map();
for (let source of this._media.querySelectorAll("source")) {
if (source.title) {
this._variants.set(source.url, source.title);
} else {
this._variants.set(source.url, (new URL(source.url)).pathname);
}
}
// Replace the original video element with a player.
this._container = document.createElement("player");
@@ -44,11 +36,31 @@ class XMediaPlayer {
this._overlay = document.createElement("overlay");
this._container.appendChild(this._overlay);
// Build the variant menu.
this._variants = document.createElement("select");
this._variants.size = 2;
this._variants.classList.add("variants", "hide");
this._overlay.appendChild(this._variants);
console.log(this._media.currentSrc);
for (let source of this._media.querySelectorAll("source")) {
let variant = document.createElement("option")
if (source.src == this._media.currentSrc) {
variant.selected = true;
}
variant.value = source.src;
if (source.title) {
variant.innerText = source.title;
} else {
variant.innerText = (new URL(source.src)).pathname;
}
this._variants.appendChild(variant);
}
// Build the control overlay.
this._controls = document.createElement("controls");
this._overlay.appendChild(this._controls);
// - Play Button
this._controlPlay = document.createElement("span");
this._controlPlay = document.createElement("div");
this._controlPlay.classList.add("play", "symbol")
this._controlPlay.tabIndex = 0;
this._controlPlay.dataset.symbol = "⏵";
@@ -71,7 +83,7 @@ class XMediaPlayer {
}
this._controls.appendChild(this._controlPlay);
// - Time Display
this._controlTime = document.createElement("span");
this._controlTime = document.createElement("div");
this._controlTime.classList.add("time");
this._controlTime.innerHTML = "00:00 / 00:00";
this._controlTime.update = () => {
@@ -129,7 +141,7 @@ class XMediaPlayer {
}
this._controls.appendChild(this._controlProgress);
// - Mute Button
this._controlMute = document.createElement("span");
this._controlMute = document.createElement("div");
this._controlMute.classList.add("mute", "symbol");
this._controlMute.tabIndex = 0;
this._controlMute.ariaLabel = "Mute";
@@ -174,15 +186,25 @@ class XMediaPlayer {
}
}
this._controls.appendChild(this._controlVolume);
// - Variant Button
this._controlVariant = document.createElement("div");
this._controlVariant.classList.add("variant", "symbol");
this._controlVariant.tabIndex = 0;
this._controlVariant.ariaLabel = "Change Variant";
this._controlVariant.dataset.symbol = "⚙";
this._controlVariant.update = () => {
this._controlVariant.value = this._media.currentSrc;
};
this._controls.appendChild(this._controlVariant);
// - Fullscreen Button
this._controlFullscreen = document.createElement("span");
this._controlFullscreen = document.createElement("div");
this._controlFullscreen.classList.add("fullscreen", "symbol");
this._controlFullscreen.tabIndex = 0;
this._controlFullscreen.ariaLabel = "Toggle Fullscreen";
this._controlFullscreen.dataset.symbol = "⛶";
this._controlFullscreen.update = () => {
if (document.fullscreenElement) {
this._controlFullscreen.dataset.symbol = "\u200F";
if (document.fullscreenElement == this._container) {
this._controlFullscreen.dataset.symbol = "\u200F";
} else {
this._controlFullscreen.dataset.symbol = "⛶";
}
@@ -209,6 +231,12 @@ class XMediaPlayer {
for (let event of ["Input", "KeyDown", "Wheel"]) {
this._controlVolume.addEventListener(event.toLowerCase(), (ev) => { this[`_on${event}`](ev); });
}
for (let event of ["Input"]) {
this._variants.addEventListener(event.toLowerCase(), (ev) => { this[`_on${event}`](ev); });
}
for (let event of ["Click", "KeyDown"]) {
this._controlVariant.addEventListener(event.toLowerCase(), (ev) => { this[`_on${event}`](ev); });
}
for (let event of ["Click", "KeyDown"]) {
this._controlFullscreen.addEventListener(event.toLowerCase(), (ev) => { this[`_on${event}`](ev); });
}
@@ -219,6 +247,7 @@ class XMediaPlayer {
this._controlProgress.update();
this._controlMute.update();
this._controlVolume.update();
this._controlVariant.update();
this._controlFullscreen.update();
// And tell the media element to load.
@@ -320,6 +349,8 @@ class XMediaPlayer {
this.toggleMute();
} else if (ev.target == this._controlFullscreen) {
this.toggleFullscreen();
} else if (ev.target == this._controlVariant) {
this.toggleVariants();
} else {
// If we can't handle this, let it fall to the next handler.
return
@@ -350,6 +381,12 @@ class XMediaPlayer {
if (["Space", "Enter"].includes(ev.code)) {
// Most likely an attempt to simulate a click.
ev.target.click();
} else if (["Escape"].includes(ev.key)) {
if (document.fullscreenElement) {
this.toggleFullscreen(false);
} else {
this.toggleTheater(false);
}
} else if (["f", "F"].includes(ev.key)) {
this._controlFullscreen.click();
} else if (["m", "M"].includes(ev.key)) {
@@ -389,6 +426,7 @@ class XMediaPlayer {
ev.stopPropagation();
}
_onInput(ev) {
this.toggleVariants(false);
if (ev.target == this._controlProgress) {
ev.preventDefault();
if (isFinite(this._media.duration)) {
@@ -407,10 +445,55 @@ class XMediaPlayer {
let vol = (val - min) / dlt;
this._media.volume = vol;
this._media.muted = (this._media.volume < 0.01);
} else if (ev.target == this._variants) {
// Switch out the video file.
// Store current state and pause.
let paused = this._media.paused;
let muted = this._media.muted;
let volume = this._media.volume;
let time = this._media.currentTime;
this._media.pause();
this._controlPlay.update();
// Tell the this._media source to begin loading.
this._media.src = this._variants.value;
this._media.load();
this._media.currentTime = time;
this._media.addEventListener("loadeddata", () => {
this._media.currentTime = time;
this._media.volume = volume;
this._media.muted = muted;
ev.preventDefault();
ev.stopPropagation();
}, {
"once": true,
"capture": true
})
this._media.addEventListener("seeked", () => {
if (paused) {
this._media.pause();
} else {
this._media.play();
}
this._controlPlay.update();
ev.preventDefault();
ev.stopPropagation();
}, {
"once": true,
"capture": true
});
}
}
_onChange(ev) {}
// Visibility
_onFullscreenChange(ev) {
this._controlFullscreen.update();
}
// Control Functions
togglePlayPause() {
if (this._media.paused) {
@@ -424,9 +507,19 @@ class XMediaPlayer {
this._media.muted = !this._media.muted;
}
toggleFullscreen() {
toggleVariants(state) {
if ((state == false) || (!this._variants.classList.contains("hide"))) {
this._variants.classList.add("hide");
} else {
this._variants.classList.remove("hide");
}
}
toggleFullscreen(state) {
if ((state == false) || (document.fullscreenElement == this._container)) {
if (document.fullscreenElement) {
document.exitFullscreen();
}
} else {
this._container.requestFullscreen();
}
@@ -500,42 +593,6 @@ async function xmr_initialize_player(el) {
}
variant.value = this._media.currentSrc;
}
{ // Hide/Show controls
el.showOverlay = function () {
el.cancelHideOverlay();
el.classList.remove("hide");
}
el.hideOverlay = function () {
}
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 (!this._media.paused && !this._media.ended && !this._media.error) {
el.delayHideOverlay();
}
});
el.hideOverlay();
}
{ // Show/Hide Audio controls without audio.
function checkAudioPresence() {
}
this._media.addEventListener("loadedmetadata", () => { checkAudioPresence() });
this._media.addEventListener("loadeddata", () => { checkAudioPresence() });
checkAudioPresence();
}
// Signal the browser to try and load some information.
this._media.load();
}
*/
+1
View File
@@ -5,6 +5,7 @@ symbols:
- code: 0023F5
- code: 0023F8
- code: 0023F9
- code: 002699
- code: 0026F6
combos:
- code: 00200F
+65
View File
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="128"
height="128"
viewBox="0 0 128 128"
version="1.1"
id="svg5"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
sodipodi:docname="u002699.svg"
style="fill: currentColor;"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showgrid="false"
inkscape:zoom="4"
inkscape:cx="13.375"
inkscape:cy="44.5"
inkscape:window-width="2560"
inkscape:window-height="1417"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2">
<linearGradient
id="linearGradient920"
inkscape:swatch="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop918" />
</linearGradient>
<linearGradient
id="linearGradient795"
inkscape:swatch="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop793" />
</linearGradient>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
id="path239"
style="fill:#ffffff;fill-opacity:1;stroke-width:8;stroke-dasharray:none"
d="M 60 8 C 58.338006 8 57 9.3380051 57 11 L 57 16.525391 A 48 48 0 0 0 46.408203 19.53125 L 43.5625 14.601562 C 42.731502 13.162232 40.904175 12.670955 39.464844 13.501953 L 32.535156 17.501953 C 31.095825 18.332951 30.606502 20.162232 31.4375 21.601562 L 34.302734 26.564453 A 48 48 0 0 0 26.466797 34.246094 L 21.601562 31.4375 C 20.162234 30.606503 18.33295 31.095827 17.501953 32.535156 L 13.501953 39.464844 C 12.670956 40.904173 13.162234 42.731503 14.601562 43.5625 L 19.474609 46.375 A 48 48 0 0 0 16.525391 57 L 11 57 C 9.3380051 57 8 58.338006 8 60 L 8 68 C 8 69.661994 9.3380051 71 11 71 L 16.525391 71 A 48 48 0 0 0 19.474609 81.625 L 14.601562 84.4375 C 13.162234 85.268497 12.670956 87.095827 13.501953 88.535156 L 17.501953 95.464844 C 18.33295 96.904173 20.162234 97.393497 21.601562 96.5625 L 26.466797 93.753906 A 48 48 0 0 0 34.246094 101.5332 L 31.4375 106.39844 C 30.606503 107.83777 31.095827 109.66705 32.535156 110.49805 L 39.464844 114.49805 C 40.904173 115.32905 42.731503 114.83777 43.5625 113.39844 L 46.375 108.52539 A 48 48 0 0 0 57 111.47461 L 57 117 C 57 118.662 58.338006 120 60 120 L 68 120 C 69.661994 120 71 118.662 71 117 L 71 111.47461 A 48 48 0 0 0 81.591797 108.46875 L 84.4375 113.39844 C 85.268498 114.83777 87.095825 115.32905 88.535156 114.49805 L 95.464844 110.49805 C 96.904175 109.66705 97.393498 107.83777 96.5625 106.39844 L 93.697266 101.43555 A 48 48 0 0 0 101.5332 93.753906 L 106.39844 96.5625 C 107.83777 97.393497 109.66705 96.904173 110.49805 95.464844 L 114.49805 88.535156 C 115.32905 87.095827 114.83777 85.268497 113.39844 84.4375 L 108.52539 81.625 A 48 48 0 0 0 111.47461 71 L 117 71 C 118.662 71 120 69.661994 120 68 L 120 60 C 120 58.338006 118.662 57 117 57 L 111.48633 57 A 48 48 0 0 0 108.61328 46.326172 L 113.39844 43.5625 C 114.83777 42.731503 115.32905 40.904173 114.49805 39.464844 L 110.49805 32.535156 C 109.66705 31.095827 107.83777 30.606503 106.39844 31.4375 L 101.61328 34.199219 A 48 48 0 0 0 93.800781 26.386719 L 96.5625 21.601562 C 97.393497 20.162234 96.904173 18.33295 95.464844 17.501953 L 88.535156 13.501953 C 87.095827 12.670956 85.268497 13.162234 84.4375 14.601562 L 81.673828 19.386719 A 48 48 0 0 0 71 16.513672 L 71 11 C 71 9.3380051 69.661994 8 68 8 L 60 8 z M 64 32 A 32 32 0 0 1 96 64 A 32 32 0 0 1 64 96 A 32 32 0 0 1 32 64 A 32 32 0 0 1 64 32 z " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB