movie-web/src/components/video/hooks/controlVideo.ts

134 lines
3.6 KiB
TypeScript
Raw Normal View History

2023-01-10 19:53:55 +01:00
import Hls from "hls.js";
import {
canChangeVolume,
canFullscreen,
canFullscreenAnyElement,
canWebkitFullscreen,
} from "@/utils/detectFeatures";
2023-01-10 01:01:51 +01:00
import fscreen from "fscreen";
2023-01-10 19:53:55 +01:00
import React, { RefObject } from "react";
import { PlayerState } from "./useVideoPlayer";
import { getStoredVolume, setStoredVolume } from "./volumeStore";
2023-01-10 01:01:51 +01:00
2023-01-08 15:37:16 +01:00
export interface PlayerControls {
play(): void;
pause(): void;
2023-01-08 16:23:42 +01:00
exitFullscreen(): void;
enterFullscreen(): void;
2023-01-08 17:51:38 +01:00
setTime(time: number): void;
setVolume(volume: number): void;
2023-01-10 19:53:55 +01:00
setSeeking(active: boolean): void;
setLeftControlsHover(hovering: boolean): void;
initPlayer(sourceUrl: string, sourceType: "m3u8" | "mp4"): void;
2023-01-08 15:37:16 +01:00
}
export const initialControls: PlayerControls = {
play: () => null,
pause: () => null,
2023-01-08 16:23:42 +01:00
enterFullscreen: () => null,
exitFullscreen: () => null,
2023-01-08 17:51:38 +01:00
setTime: () => null,
setVolume: () => null,
2023-01-10 19:53:55 +01:00
setSeeking: () => null,
setLeftControlsHover: () => null,
initPlayer: () => null,
2023-01-08 15:37:16 +01:00
};
2023-01-08 16:23:42 +01:00
export function populateControls(
2023-01-10 19:53:55 +01:00
playerEl: HTMLVideoElement,
wrapperEl: HTMLDivElement,
update: (s: React.SetStateAction<PlayerState>) => void,
state: RefObject<PlayerState>
2023-01-08 16:23:42 +01:00
): PlayerControls {
2023-01-10 19:53:55 +01:00
const player = playerEl;
const wrapper = wrapperEl;
2023-01-08 15:37:16 +01:00
return {
play() {
player.play();
},
pause() {
player.pause();
},
2023-01-08 16:23:42 +01:00
enterFullscreen() {
2023-01-10 19:53:55 +01:00
if (!canFullscreen() || fscreen.fullscreenElement) return;
if (canFullscreenAnyElement()) {
2023-01-10 01:01:51 +01:00
fscreen.requestFullscreen(wrapper);
return;
}
2023-01-10 19:53:55 +01:00
if (canWebkitFullscreen()) {
2023-01-10 01:01:51 +01:00
(player as any).webkitEnterFullscreen();
}
2023-01-08 16:23:42 +01:00
},
exitFullscreen() {
2023-01-10 01:01:51 +01:00
if (!fscreen.fullscreenElement) return;
fscreen.exitFullscreen();
2023-01-08 16:23:42 +01:00
},
2023-01-08 17:51:38 +01:00
setTime(t) {
// clamp time between 0 and max duration
let time = Math.min(t, player.duration);
time = Math.max(0, time);
2023-01-10 19:53:55 +01:00
if (Number.isNaN(time)) return;
// update state
2023-01-08 17:51:38 +01:00
player.currentTime = time;
2023-01-10 19:53:55 +01:00
update((s) => ({ ...s, time }));
2023-01-08 17:51:38 +01:00
},
2023-01-10 19:53:55 +01:00
async setVolume(v) {
2023-01-08 17:51:38 +01:00
// clamp time between 0 and 1
let volume = Math.min(v, 1);
volume = Math.max(0, volume);
2023-01-10 19:53:55 +01:00
// update state
if (await canChangeVolume()) player.volume = volume;
update((s) => ({ ...s, volume }));
// update localstorage
setStoredVolume(volume);
},
setSeeking(active) {
const currentState = state.current;
if (!currentState) return;
// if it was playing when starting to seek, play again
if (!active) {
if (!currentState.pausedWhenSeeking) this.play();
return;
}
// when seeking we pause the video
update((s) => ({ ...s, pausedWhenSeeking: s.isPaused }));
this.pause();
},
setLeftControlsHover(hovering) {
update((s) => ({ ...s, leftControlHovering: hovering }));
},
initPlayer(sourceUrl: string, sourceType: "m3u8" | "mp4") {
this.setVolume(getStoredVolume());
if (sourceType === "m3u8") {
if (player.canPlayType("application/vnd.apple.mpegurl")) {
player.src = sourceUrl;
} else {
// HLS support
if (!Hls.isSupported()) throw new Error("HLS not supported"); // TODO handle errors
const hls = new Hls();
hls.on(Hls.Events.ERROR, (event, data) => {
// eslint-disable-next-line no-alert
if (data.fatal) alert("HLS fatal error");
console.error("HLS error", data); // TODO handle errors
});
hls.attachMedia(player);
hls.loadSource(sourceUrl);
}
} else if (sourceType === "mp4") {
player.src = sourceUrl;
}
2023-01-08 17:51:38 +01:00
},
2023-01-08 15:37:16 +01:00
};
}