1
0
Fork 0
mirror of https://github.com/sussy-code/smov.git synced 2024-12-22 14:57:40 +01:00
smov/__old/hooks/controlVideo.ts

205 lines
5.3 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";
import { MWStreamType } from "@/backend/helpers/streams";
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
interface ShowData {
current?: {
episodeId: string;
seasonId: string;
};
isSeries: boolean;
seasons?: {
id: string;
number: number;
title: string;
episodes?: {
id: string;
number: number;
title: string;
}[];
}[];
}
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: MWStreamType): void;
setShowData(data: ShowData): void;
setCurrentEpisode(sId: string, eId: string): void;
startAirplay(): void;
openPopout(id: string): void;
closePopout(): 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,
setShowData: () => null,
startAirplay: () => null,
setCurrentEpisode: () => null,
openPopout: () => null,
closePopout: () => 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 }));
},
openPopout(id: string) {
update((s) => ({ ...s, popout: id }));
},
closePopout() {
update((s) => ({ ...s, popout: null }));
},
setShowData(data) {
update((s) => ({ ...s, seasonData: data }));
},
setCurrentEpisode(sId: string, eId: string) {
update((s) => ({
...s,
seasonData: {
...s.seasonData,
current: {
seasonId: sId,
episodeId: eId,
},
},
}));
},
startAirplay() {
const videoPlayer = player as any;
if (videoPlayer.webkitShowPlaybackTargetPicker)
videoPlayer.webkitShowPlaybackTargetPicker();
},
initPlayer(sourceUrl: string, sourceType: MWStreamType) {
2023-01-10 19:53:55 +01:00
this.setVolume(getStoredVolume());
if (sourceType === MWStreamType.HLS) {
2023-01-10 19:53:55 +01:00
if (player.canPlayType("application/vnd.apple.mpegurl")) {
player.src = sourceUrl;
} else {
// HLS support
2023-01-15 16:51:55 +01:00
if (!Hls.isSupported()) {
update((s) => ({
...s,
error: {
name: `Not supported`,
description: "Your browser does not support HLS video",
},
}));
return;
}
2023-01-10 19:53:55 +01:00
2023-01-26 14:31:50 +01:00
const hls = new Hls({ enableWorker: false });
2023-01-10 19:53:55 +01:00
hls.on(Hls.Events.ERROR, (event, data) => {
2023-01-15 16:51:55 +01:00
if (data.fatal) {
update((s) => ({
...s,
error: {
name: `error ${data.details}`,
description: data.error?.message ?? "Something went wrong",
},
}));
}
console.error("HLS error", data);
2023-01-10 19:53:55 +01:00
});
hls.attachMedia(player);
hls.loadSource(sourceUrl);
}
} else if (sourceType === MWStreamType.MP4) {
2023-01-10 19:53:55 +01:00
player.src = sourceUrl;
}
2023-01-08 17:51:38 +01:00
},
2023-01-08 15:37:16 +01:00
};
}