This commit is contained in:
Jip Fr 2023-10-21 19:37:44 +02:00
parent fcec845f21
commit 78ae77392c
5 changed files with 43 additions and 0 deletions

View File

@ -0,0 +1,14 @@
import { Icons } from "@/components/Icon";
import { VideoPlayerButton } from "@/components/player/internals/Button";
import { usePlayerStore } from "@/stores/player/store";
export function Pip() {
const display = usePlayerStore((s) => s.display);
return (
<VideoPlayerButton
onClick={() => display?.togglePictureInPicture()}
icon={Icons.PICTURE_IN_PICTURE}
/>
);
}

View File

@ -1,5 +1,6 @@
export * from "./Pause"; export * from "./Pause";
export * from "./Fullscreen"; export * from "./Fullscreen";
export * from "./Pip";
export * from "./ProgressBar"; export * from "./ProgressBar";
export * from "./Skips"; export * from "./Skips";
export * from "./Time"; export * from "./Time";

View File

@ -42,6 +42,14 @@ function hlsLevelsToQualities(levels: Level[]): SourceQuality[] {
.filter((v): v is SourceQuality => !!v); .filter((v): v is SourceQuality => !!v);
} }
export function canWebkitPictureInPicture(): boolean {
return "webkitSupportsPresentationMode" in document.createElement("video");
}
export function canPictureInPicture(): boolean {
return "pictureInPictureEnabled" in document;
}
export function makeVideoElementDisplayInterface(): DisplayInterface { export function makeVideoElementDisplayInterface(): DisplayInterface {
const { emit, on, off } = makeEmitter<DisplayInterfaceEvents>(); const { emit, on, off } = makeEmitter<DisplayInterfaceEvents>();
let source: LoadableSource | null = null; let source: LoadableSource | null = null;
@ -306,6 +314,24 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
} }
} }
}, },
togglePictureInPicture() {
if (!videoElement) return;
if (canWebkitPictureInPicture()) {
const webkitPlayer = videoElement as any;
webkitPlayer.webkitSetPresentationMode(
webkitPlayer.webkitPresentationMode === "picture-in-picture"
? "inline"
: "picture-in-picture"
);
}
if (canPictureInPicture()) {
if (videoElement !== document.pictureInPictureElement) {
videoElement.requestPictureInPicture();
} else {
document.exitPictureInPicture();
}
}
},
startAirplay() { startAirplay() {
const videoPlayer = videoElement as any; const videoPlayer = videoElement as any;
if (videoPlayer && videoPlayer.webkitShowPlaybackTargetPicker) { if (videoPlayer && videoPlayer.webkitShowPlaybackTargetPicker) {

View File

@ -35,6 +35,7 @@ export interface DisplayInterface extends Listener<DisplayInterfaceEvents> {
processVideoElement(video: HTMLVideoElement): void; processVideoElement(video: HTMLVideoElement): void;
processContainerElement(container: HTMLElement): void; processContainerElement(container: HTMLElement): void;
toggleFullscreen(): void; toggleFullscreen(): void;
togglePictureInPicture(): void;
setSeeking(active: boolean): void; setSeeking(active: boolean): void;
setVolume(vol: number): void; setVolume(vol: number): void;
setTime(t: number): void; setTime(t: number): void;

View File

@ -79,6 +79,7 @@ export function PlayerPart(props: PlayerPartProps) {
</Player.LeftSideControls> </Player.LeftSideControls>
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<Player.Episodes /> <Player.Episodes />
<Player.Pip />
<Player.Airplay /> <Player.Airplay />
<Player.Chromecast /> <Player.Chromecast />
<Player.Settings /> <Player.Settings />