Fix videojs-vr issues (#3793)

* Add videojs-vr.d.ts
* Improve dynamic VR toggling
This commit is contained in:
DingDongSoLong4
2023-06-02 03:15:33 +02:00
committed by GitHub
parent c8a796e125
commit 4acf843229
3 changed files with 181 additions and 25 deletions

116
ui/v2.5/src/@types/videojs-vr.d.ts vendored Normal file
View File

@@ -0,0 +1,116 @@
/* eslint-disable @typescript-eslint/naming-convention */
declare module "videojs-vr" {
import videojs from "video.js";
declare function videojsVR(options?: videojsVR.Options): videojsVR.Plugin;
declare namespace videojsVR {
const VERSION: typeof videojs.VERSION;
type ProjectionType =
// The video is half sphere and the user should not be able to look behind themselves
| "180"
// Used for side-by-side 180 videos The video is half sphere and the user should not be able to look behind themselves
| "180_LR"
// Used for monoscopic 180 videos The video is half sphere and the user should not be able to look behind themselves
| "180_MONO"
// The video is a sphere
| "360"
| "Sphere"
| "equirectangular"
// The video is a cube
| "360_CUBE"
| "Cube"
// This video is not a 360 video
| "NONE"
// Check player.mediainfo.projection to see if the current video is a 360 video.
| "AUTO"
// Used for side-by-side 360 videos
| "360_LR"
// Used for top-to-bottom 360 videos
| "360_TB"
// Used for Equi-Angular Cubemap videos
| "EAC"
// Used for side-by-side Equi-Angular Cubemap videos
| "EAC_LR";
interface Options {
/**
* Force the cardboard button to display on all devices even if we don't think they support it.
*
* @default false
*/
forceCardboard?: boolean;
/**
* Whether motion/gyro controls should be enabled.
*
* @default true on iOS and Android
*/
motionControls?: boolean;
/**
* Defines the projection type.
*
* @default "AUTO"
*/
projection?: ProjectionType;
/**
* This alters the number of segments in the spherical mesh onto which equirectangular videos are projected.
* The default is 32 but in some circumstances you may notice artifacts and need to increase this number.
*
* @default 32
*/
sphereDetail?: number;
/**
* Enable debug logging for this plugin
*
* @default false
*/
debug?: boolean;
/**
* Use this property to pass the Omnitone library object to the plugin. Please be aware of, the Omnitone library is not included in the build files.
*/
omnitone?: object;
/**
* Default options for the Omnitone library. Please check available options on https://github.com/GoogleChrome/omnitone
*/
omnitoneOptions?: object;
/**
* Feature to disable the togglePlay manually. This functionality is useful in live events so that users cannot stop the live, but still have a controlBar available.
*
* @default false
*/
disableTogglePlay?: boolean;
}
interface PlayerMediaInfo {
/**
* This should be set on a source-by-source basis to turn 360 videos on an off depending upon the video.
* Note that AUTO is the same as NONE for player.mediainfo.projection.
*/
projection?: ProjectionType;
}
class Plugin extends videojs.Plugin {
setProjection(projection: ProjectionType): void;
init(): void;
reset(): void;
}
}
export = videojsVR;
declare module "video.js" {
interface VideoJsPlayer {
vr: typeof videojsVR;
mediainfo?: videojsVR.PlayerMediaInfo;
}
}
}

View File

@@ -267,16 +267,6 @@ export const ScenePlayer: React.FC<IScenePlayerProps> = ({
// Initialize VideoJS player
useEffect(() => {
function isVrScene() {
if (!scene?.id || !vrTag) return false;
return scene?.tags.some((tag) => {
if (vrTag == tag.name) {
return true;
}
});
}
const options: VideoJsPlayerOptions = {
id: VIDEO_PLAYER_ID,
controls: true,
@@ -330,9 +320,7 @@ export const ScenePlayer: React.FC<IScenePlayerProps> = ({
},
skipButtons: {},
trackActivity: {},
vrMenu: {
showButton: isVrScene(),
},
vrMenu: {},
},
};
@@ -364,7 +352,8 @@ export const ScenePlayer: React.FC<IScenePlayerProps> = ({
// reset sceneId to force reload sources
sceneId.current = undefined;
};
}, [scene, vrTag]);
// empty deps - only init once
}, []);
useEffect(() => {
const player = getPlayer();
@@ -388,6 +377,21 @@ export const ScenePlayer: React.FC<IScenePlayerProps> = ({
scene?.paths.funscript,
]);
useEffect(() => {
const player = getPlayer();
if (!player) return;
const vrMenu = player.vrMenu();
let showButton = false;
if (scene && vrTag) {
showButton = scene.tags.some((tag) => vrTag === tag.name);
}
vrMenu.setShowButton(showButton);
}, [getPlayer, scene, vrTag]);
// Player event handlers
useEffect(() => {
const player = getPlayer();

View File

@@ -1,6 +1,9 @@
/* eslint-disable @typescript-eslint/naming-convention */
import videojs, { VideoJsPlayer } from "video.js";
import "videojs-vr";
// separate type import, otherwise typescript elides the above import
// and the plugin does not get initialized
import type { ProjectionType, Plugin as VideoJsVRPlugin } from "videojs-vr";
export interface VRMenuOptions {
/**
@@ -15,7 +18,7 @@ enum VRType {
Off = "Off",
}
const vrTypeProjection = {
const vrTypeProjection: Record<VRType, ProjectionType> = {
[VRType.Spherical]: "360",
[VRType.Off]: "NONE",
};
@@ -29,7 +32,7 @@ class VRMenuItem extends videojs.getComponent("MenuItem") {
public isSelected = false;
constructor(parent: VRMenuButton, type: VRType) {
const options = {} as videojs.MenuItemOptions;
const options: videojs.MenuItemOptions = {};
options.selectable = true;
options.multiSelectable = false;
options.label = type;
@@ -105,27 +108,61 @@ class VRMenuButton extends videojs.getComponent("MenuButton") {
class VRMenuPlugin extends videojs.getPlugin("plugin") {
private menu: VRMenuButton;
private showButton: boolean;
private vr?: VideoJsVRPlugin;
constructor(player: VideoJsPlayer, options: VRMenuOptions) {
super(player);
this.menu = new VRMenuButton(player);
this.showButton = options.showButton ?? false;
if (isVrDevice() || !options.showButton) return;
if (isVrDevice()) return;
this.vr = this.player.vr();
this.menu.on("typeselected", (_, type: VRType) => {
const projection = vrTypeProjection[type];
player.vr({ projection });
player.load();
this.loadVR(type);
});
player.on("ready", () => {
const { controlBar } = player;
const fullscreenToggle = controlBar.getChild("fullscreenToggle")!.el();
controlBar.addChild(this.menu);
controlBar.el().insertBefore(this.menu.el(), fullscreenToggle);
if (this.showButton) {
this.addButton();
}
});
}
private loadVR(type: VRType) {
const projection = vrTypeProjection[type];
this.vr?.setProjection(projection);
this.vr?.init();
}
private addButton() {
const { controlBar } = this.player;
const fullscreenToggle = controlBar.getChild("fullscreenToggle")!.el();
controlBar.addChild(this.menu);
controlBar.el().insertBefore(this.menu.el(), fullscreenToggle);
}
private removeButton() {
const { controlBar } = this.player;
controlBar.removeChild(this.menu);
}
public setShowButton(showButton: boolean) {
if (isVrDevice()) return;
if (showButton === this.showButton) return;
this.showButton = showButton;
if (showButton) {
this.addButton();
} else {
this.removeButton();
this.loadVR(VRType.Off);
}
}
}
// Register the plugin with video.js.
@@ -136,7 +173,6 @@ videojs.registerPlugin("vrMenu", VRMenuPlugin);
declare module "video.js" {
interface VideoJsPlayer {
vrMenu: () => VRMenuPlugin;
vr: (options: Object) => void;
}
interface VideoJsPlayerPluginOptions {
vrMenu?: VRMenuOptions;