mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Loop and autostart flags. Save interface options (#230)
This commit is contained in:
@@ -13,6 +13,10 @@ fragment ConfigGeneralData on ConfigGeneralResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fragment ConfigInterfaceData on ConfigInterfaceResult {
|
fragment ConfigInterfaceData on ConfigInterfaceResult {
|
||||||
|
soundOnPreview
|
||||||
|
wallShowTitle
|
||||||
|
maximumLoopDuration
|
||||||
|
autostartVideo
|
||||||
css
|
css
|
||||||
cssEnabled
|
cssEnabled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,12 +58,28 @@ type ConfigGeneralResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input ConfigInterfaceInput {
|
input ConfigInterfaceInput {
|
||||||
|
"""Enable sound on mouseover previews"""
|
||||||
|
soundOnPreview: Boolean
|
||||||
|
"""Show title and tags in wall view"""
|
||||||
|
wallShowTitle: Boolean
|
||||||
|
"""Maximum duration (in seconds) in which a scene video will loop in the scene player"""
|
||||||
|
maximumLoopDuration: Int
|
||||||
|
"""If true, video will autostart on load in the scene player"""
|
||||||
|
autostartVideo: Boolean
|
||||||
"""Custom CSS"""
|
"""Custom CSS"""
|
||||||
css: String
|
css: String
|
||||||
cssEnabled: Boolean
|
cssEnabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigInterfaceResult {
|
type ConfigInterfaceResult {
|
||||||
|
"""Enable sound on mouseover previews"""
|
||||||
|
soundOnPreview: Boolean
|
||||||
|
"""Show title and tags in wall view"""
|
||||||
|
wallShowTitle: Boolean
|
||||||
|
"""Maximum duration (in seconds) in which a scene video will loop in the scene player"""
|
||||||
|
maximumLoopDuration: Int
|
||||||
|
"""If true, video will autostart on load in the scene player"""
|
||||||
|
autostartVideo: Boolean
|
||||||
"""Custom CSS"""
|
"""Custom CSS"""
|
||||||
css: String
|
css: String
|
||||||
cssEnabled: Boolean
|
cssEnabled: Boolean
|
||||||
|
|||||||
@@ -82,6 +82,22 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models.ConfigInterfaceInput) (*models.ConfigInterfaceResult, error) {
|
func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models.ConfigInterfaceInput) (*models.ConfigInterfaceResult, error) {
|
||||||
|
if input.SoundOnPreview != nil {
|
||||||
|
config.Set(config.SoundOnPreview, *input.SoundOnPreview)
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.WallShowTitle != nil {
|
||||||
|
config.Set(config.WallShowTitle, *input.WallShowTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.MaximumLoopDuration != nil {
|
||||||
|
config.Set(config.MaximumLoopDuration, *input.MaximumLoopDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.AutostartVideo != nil {
|
||||||
|
config.Set(config.AutostartVideo, *input.AutostartVideo)
|
||||||
|
}
|
||||||
|
|
||||||
css := ""
|
css := ""
|
||||||
|
|
||||||
if input.CSS != nil {
|
if input.CSS != nil {
|
||||||
|
|||||||
@@ -49,10 +49,19 @@ func makeConfigGeneralResult() *models.ConfigGeneralResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeConfigInterfaceResult() *models.ConfigInterfaceResult {
|
func makeConfigInterfaceResult() *models.ConfigInterfaceResult {
|
||||||
|
soundOnPreview := config.GetSoundOnPreview()
|
||||||
|
wallShowTitle := config.GetWallShowTitle()
|
||||||
|
maximumLoopDuration := config.GetMaximumLoopDuration()
|
||||||
|
autostartVideo := config.GetAutostartVideo()
|
||||||
css := config.GetCSS()
|
css := config.GetCSS()
|
||||||
cssEnabled := config.GetCSSEnabled()
|
cssEnabled := config.GetCSSEnabled()
|
||||||
|
|
||||||
return &models.ConfigInterfaceResult{
|
return &models.ConfigInterfaceResult{
|
||||||
CSS: &css,
|
SoundOnPreview: &soundOnPreview,
|
||||||
CSSEnabled: &cssEnabled,
|
WallShowTitle: &wallShowTitle,
|
||||||
|
MaximumLoopDuration: &maximumLoopDuration,
|
||||||
|
AutostartVideo: &autostartVideo,
|
||||||
|
CSS: &css,
|
||||||
|
CSSEnabled: &cssEnabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ const MaxStreamingTranscodeSize = "max_streaming_transcode_size"
|
|||||||
const Host = "host"
|
const Host = "host"
|
||||||
const Port = "port"
|
const Port = "port"
|
||||||
|
|
||||||
|
// Interface options
|
||||||
|
const SoundOnPreview = "sound_on_preview"
|
||||||
|
const WallShowTitle = "wall_show_title"
|
||||||
|
const MaximumLoopDuration = "maximum_loop_duration"
|
||||||
|
const AutostartVideo = "autostart_video"
|
||||||
const CSSEnabled = "cssEnabled"
|
const CSSEnabled = "cssEnabled"
|
||||||
|
|
||||||
// Logging options
|
// Logging options
|
||||||
@@ -165,6 +170,27 @@ func ValidateCredentials(username string, password string) bool {
|
|||||||
return username == authUser && err == nil
|
return username == authUser && err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interface options
|
||||||
|
func GetSoundOnPreview() bool {
|
||||||
|
viper.SetDefault(SoundOnPreview, true)
|
||||||
|
return viper.GetBool(SoundOnPreview)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetWallShowTitle() bool {
|
||||||
|
viper.SetDefault(WallShowTitle, true)
|
||||||
|
return viper.GetBool(WallShowTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMaximumLoopDuration() int {
|
||||||
|
viper.SetDefault(MaximumLoopDuration, 0)
|
||||||
|
return viper.GetInt(MaximumLoopDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAutostartVideo() bool {
|
||||||
|
viper.SetDefault(AutostartVideo, false)
|
||||||
|
return viper.GetBool(AutostartVideo)
|
||||||
|
}
|
||||||
|
|
||||||
func GetCSSPath() string {
|
func GetCSSPath() string {
|
||||||
// use custom.css in the same directory as the config file
|
// use custom.css in the same directory as the config file
|
||||||
configFileUsed := viper.ConfigFileUsed()
|
configFileUsed := viper.ConfigFileUsed()
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import {
|
|||||||
FormGroup,
|
FormGroup,
|
||||||
H4,
|
H4,
|
||||||
Spinner,
|
Spinner,
|
||||||
TextArea
|
TextArea,
|
||||||
|
NumericInput
|
||||||
} from "@blueprintjs/core";
|
} from "@blueprintjs/core";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, { FunctionComponent, useEffect, useState } from "react";
|
import React, { FunctionComponent, useEffect, useState } from "react";
|
||||||
import { useInterfaceLocalForage } from "../../hooks/LocalForage";
|
|
||||||
import { StashService } from "../../core/StashService";
|
import { StashService } from "../../core/StashService";
|
||||||
import { ErrorUtils } from "../../utils/errors";
|
import { ErrorUtils } from "../../utils/errors";
|
||||||
import { ToastUtils } from "../../utils/toasts";
|
import { ToastUtils } from "../../utils/toasts";
|
||||||
@@ -17,12 +17,19 @@ import { ToastUtils } from "../../utils/toasts";
|
|||||||
interface IProps {}
|
interface IProps {}
|
||||||
|
|
||||||
export const SettingsInterfacePanel: FunctionComponent<IProps> = () => {
|
export const SettingsInterfacePanel: FunctionComponent<IProps> = () => {
|
||||||
const {data, setData} = useInterfaceLocalForage();
|
|
||||||
const config = StashService.useConfiguration();
|
const config = StashService.useConfiguration();
|
||||||
|
const [soundOnPreview, setSoundOnPreview] = useState<boolean>();
|
||||||
|
const [wallShowTitle, setWallShowTitle] = useState<boolean>();
|
||||||
|
const [maximumLoopDuration, setMaximumLoopDuration] = useState<number>(0);
|
||||||
|
const [autostartVideo, setAutostartVideo] = useState<boolean>();
|
||||||
const [css, setCSS] = useState<string>();
|
const [css, setCSS] = useState<string>();
|
||||||
const [cssEnabled, setCSSEnabled] = useState<boolean>();
|
const [cssEnabled, setCSSEnabled] = useState<boolean>();
|
||||||
|
|
||||||
const updateInterfaceConfig = StashService.useConfigureInterface({
|
const updateInterfaceConfig = StashService.useConfigureInterface({
|
||||||
|
soundOnPreview,
|
||||||
|
wallShowTitle,
|
||||||
|
maximumLoopDuration,
|
||||||
|
autostartVideo,
|
||||||
css,
|
css,
|
||||||
cssEnabled
|
cssEnabled
|
||||||
});
|
});
|
||||||
@@ -30,6 +37,11 @@ export const SettingsInterfacePanel: FunctionComponent<IProps> = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!config.data || !config.data.configuration || !!config.error) { return; }
|
if (!config.data || !config.data.configuration || !!config.error) { return; }
|
||||||
if (!!config.data.configuration.interface) {
|
if (!!config.data.configuration.interface) {
|
||||||
|
let iCfg = config.data.configuration.interface;
|
||||||
|
setSoundOnPreview(iCfg.soundOnPreview !== undefined ? iCfg.soundOnPreview : true);
|
||||||
|
setWallShowTitle(iCfg.wallShowTitle !== undefined ? iCfg.wallShowTitle : true);
|
||||||
|
setMaximumLoopDuration(iCfg.maximumLoopDuration || 0);
|
||||||
|
setAutostartVideo(iCfg.autostartVideo !== undefined ? iCfg.autostartVideo : false);
|
||||||
setCSS(config.data.configuration.interface.css || "");
|
setCSS(config.data.configuration.interface.css || "");
|
||||||
setCSSEnabled(config.data.configuration.interface.cssEnabled || false);
|
setCSSEnabled(config.data.configuration.interface.cssEnabled || false);
|
||||||
}
|
}
|
||||||
@@ -55,25 +67,40 @@ export const SettingsInterfacePanel: FunctionComponent<IProps> = () => {
|
|||||||
helperText="Configuration for wall items"
|
helperText="Configuration for wall items"
|
||||||
>
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={!!data ? data.wall.textContainerEnabled : true}
|
checked={wallShowTitle}
|
||||||
label="Display title and tags"
|
label="Display title and tags"
|
||||||
onChange={() => {
|
onChange={() => setWallShowTitle(!wallShowTitle)}
|
||||||
if (!data) { return; }
|
|
||||||
const newSettings = _.cloneDeep(data);
|
|
||||||
newSettings.wall.textContainerEnabled = !data.wall.textContainerEnabled;
|
|
||||||
setData(newSettings);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={!!data ? data.wall.soundEnabled : true}
|
checked={soundOnPreview}
|
||||||
label="Enable sound"
|
label="Enable sound"
|
||||||
|
onChange={() => setSoundOnPreview(!soundOnPreview)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup
|
||||||
|
label="Scene Player"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={autostartVideo}
|
||||||
|
label="Auto-start video"
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
if (!data) { return; }
|
setAutostartVideo(!autostartVideo)
|
||||||
const newSettings = _.cloneDeep(data);
|
|
||||||
newSettings.wall.soundEnabled = !data.wall.soundEnabled;
|
|
||||||
setData(newSettings);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormGroup
|
||||||
|
label="Maximum loop duration"
|
||||||
|
helperText="Maximum scene duration - in seconds - where scene player will loop the video - 0 to disable"
|
||||||
|
>
|
||||||
|
<NumericInput
|
||||||
|
value={maximumLoopDuration}
|
||||||
|
type="number"
|
||||||
|
onValueChange={(value: number) => setMaximumLoopDuration(value)}
|
||||||
|
min={0}
|
||||||
|
minorStepSize={1}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
@@ -94,10 +121,10 @@ export const SettingsInterfacePanel: FunctionComponent<IProps> = () => {
|
|||||||
fill={true}
|
fill={true}
|
||||||
rows={16}>
|
rows={16}>
|
||||||
</TextArea>
|
</TextArea>
|
||||||
|
|
||||||
<Divider />
|
|
||||||
<Button intent="primary" onClick={() => onSave()}>Save</Button>
|
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
<Button intent="primary" onClick={() => onSave()}>Save</Button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import _ from "lodash";
|
|||||||
import React, { FunctionComponent, useRef, useState, useEffect } from "react";
|
import React, { FunctionComponent, useRef, useState, useEffect } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import * as GQL from "../../core/generated-graphql";
|
import * as GQL from "../../core/generated-graphql";
|
||||||
import { useInterfaceLocalForage } from "../../hooks/LocalForage";
|
|
||||||
import { VideoHoverHook } from "../../hooks/VideoHover";
|
import { VideoHoverHook } from "../../hooks/VideoHover";
|
||||||
import { TextUtils } from "../../utils/text";
|
import { TextUtils } from "../../utils/text";
|
||||||
import { NavigationUtils } from "../../utils/navigation";
|
import { NavigationUtils } from "../../utils/navigation";
|
||||||
|
import { StashService } from "../../core/StashService";
|
||||||
|
|
||||||
interface IWallItemProps {
|
interface IWallItemProps {
|
||||||
scene?: GQL.SlimSceneDataFragment;
|
scene?: GQL.SlimSceneDataFragment;
|
||||||
@@ -29,9 +29,9 @@ export const WallItem: FunctionComponent<IWallItemProps> = (props: IWallItemProp
|
|||||||
const [screenshotPath, setScreenshotPath] = useState<string>("");
|
const [screenshotPath, setScreenshotPath] = useState<string>("");
|
||||||
const [title, setTitle] = useState<string>("");
|
const [title, setTitle] = useState<string>("");
|
||||||
const [tags, setTags] = useState<JSX.Element[]>([]);
|
const [tags, setTags] = useState<JSX.Element[]>([]);
|
||||||
|
const config = StashService.useConfiguration();
|
||||||
const videoHoverHook = VideoHoverHook.useVideoHover({resetOnMouseLeave: true});
|
const videoHoverHook = VideoHoverHook.useVideoHover({resetOnMouseLeave: true});
|
||||||
const interfaceSettings = useInterfaceLocalForage();
|
const showTextContainer = !!config.data ? config.data.configuration.interface.wallShowTitle : true;
|
||||||
const showTextContainer = !!interfaceSettings.data ? interfaceSettings.data.wall.textContainerEnabled : true;
|
|
||||||
|
|
||||||
function onMouseEnter() {
|
function onMouseEnter() {
|
||||||
VideoHoverHook.onMouseEnter(videoHoverHook);
|
VideoHoverHook.onMouseEnter(videoHoverHook);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Hotkey, Hotkeys, HotkeysTarget } from "@blueprintjs/core";
|
import { Hotkey, Hotkeys, HotkeysTarget } from "@blueprintjs/core";
|
||||||
import React from "react";
|
import React, { Component, FunctionComponent } from "react";
|
||||||
import ReactJWPlayer from "react-jw-player";
|
import ReactJWPlayer from "react-jw-player";
|
||||||
import * as GQL from "../../../core/generated-graphql";
|
import * as GQL from "../../../core/generated-graphql";
|
||||||
import { SceneHelpers } from "../helpers";
|
import { SceneHelpers } from "../helpers";
|
||||||
import { ScenePlayerScrubber } from "./ScenePlayerScrubber";
|
import { ScenePlayerScrubber } from "./ScenePlayerScrubber";
|
||||||
import videojs from "video.js";
|
import videojs from "video.js";
|
||||||
import "video.js/dist/video-js.css";
|
import "video.js/dist/video-js.css";
|
||||||
|
import { StashService } from "../../../core/StashService";
|
||||||
|
|
||||||
interface IScenePlayerProps {
|
interface IScenePlayerProps {
|
||||||
scene: GQL.SceneDataFragment;
|
scene: GQL.SceneDataFragment;
|
||||||
@@ -13,21 +14,26 @@ interface IScenePlayerProps {
|
|||||||
onReady?: any;
|
onReady?: any;
|
||||||
onSeeked?: any;
|
onSeeked?: any;
|
||||||
onTime?: any;
|
onTime?: any;
|
||||||
|
config?: GQL.ConfigInterfaceDataFragment;
|
||||||
}
|
}
|
||||||
interface IScenePlayerState {
|
interface IScenePlayerState {
|
||||||
scrubberPosition: number;
|
scrubberPosition: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VideoJSPlayer extends React.Component<IScenePlayerProps> {
|
interface IVideoJSPlayerProps extends IScenePlayerProps {
|
||||||
|
videoJSOptions: videojs.PlayerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VideoJSPlayer extends React.Component<IVideoJSPlayerProps> {
|
||||||
private player: any;
|
private player: any;
|
||||||
private videoNode: any;
|
private videoNode: any;
|
||||||
|
|
||||||
constructor(props: IScenePlayerProps) {
|
constructor(props: IVideoJSPlayerProps) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.player = videojs(this.videoNode);
|
this.player = videojs(this.videoNode, this.props.videoJSOptions);
|
||||||
|
|
||||||
// dirty hack - make this player look like JWPlayer
|
// dirty hack - make this player look like JWPlayer
|
||||||
this.player.seek = this.player.currentTime;
|
this.player.seek = this.player.currentTime;
|
||||||
@@ -92,7 +98,7 @@ export class VideoJSPlayer extends React.Component<IScenePlayerProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@HotkeysTarget
|
@HotkeysTarget
|
||||||
export class ScenePlayer extends React.Component<IScenePlayerProps, IScenePlayerState> {
|
export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePlayerState> {
|
||||||
private player: any;
|
private player: any;
|
||||||
private lastTime = 0;
|
private lastTime = 0;
|
||||||
|
|
||||||
@@ -116,7 +122,7 @@ export class ScenePlayer extends React.Component<IScenePlayerProps, IScenePlayer
|
|||||||
|
|
||||||
renderPlayer() {
|
renderPlayer() {
|
||||||
if (this.props.scene.is_streamable) {
|
if (this.props.scene.is_streamable) {
|
||||||
const config = this.makeConfig(this.props.scene);
|
const config = this.makeJWPlayerConfig(this.props.scene);
|
||||||
return (
|
return (
|
||||||
<ReactJWPlayer
|
<ReactJWPlayer
|
||||||
playerId={SceneHelpers.getJWPlayerId()}
|
playerId={SceneHelpers.getJWPlayerId()}
|
||||||
@@ -128,15 +134,20 @@ export class ScenePlayer extends React.Component<IScenePlayerProps, IScenePlayer
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
// don't render videoJS until config is loaded
|
||||||
<VideoJSPlayer
|
if (this.props.config) {
|
||||||
scene={this.props.scene}
|
const config = this.makeVideoJSConfig(this.props.scene);
|
||||||
timestamp={this.props.timestamp}
|
return (
|
||||||
onReady={this.onReady}
|
<VideoJSPlayer
|
||||||
onSeeked={this.onSeeked}
|
videoJSOptions={config}
|
||||||
onTime={this.onTime}>
|
scene={this.props.scene}
|
||||||
</VideoJSPlayer>
|
timestamp={this.props.timestamp}
|
||||||
)
|
onReady={this.onReady}
|
||||||
|
onSeeked={this.onSeeked}
|
||||||
|
onTime={this.onTime}>
|
||||||
|
</VideoJSPlayer>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,8 +205,16 @@ export class ScenePlayer extends React.Component<IScenePlayerProps, IScenePlayer
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private makeConfig(scene: GQL.SceneDataFragment) {
|
private shouldRepeat(scene: GQL.SceneDataFragment) {
|
||||||
|
let maxLoopDuration = this.props.config ? this.props.config.maximumLoopDuration : 0;
|
||||||
|
return !!scene.file.duration && !!maxLoopDuration && scene.file.duration < maxLoopDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private makeJWPlayerConfig(scene: GQL.SceneDataFragment) {
|
||||||
if (!scene.paths.stream) { return {}; }
|
if (!scene.paths.stream) { return {}; }
|
||||||
|
|
||||||
|
let repeat = this.shouldRepeat(scene);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
file: scene.paths.stream,
|
file: scene.paths.stream,
|
||||||
image: scene.paths.screenshot,
|
image: scene.paths.screenshot,
|
||||||
@@ -216,12 +235,24 @@ export class ScenePlayer extends React.Component<IScenePlayerProps, IScenePlayer
|
|||||||
},
|
},
|
||||||
cast: {},
|
cast: {},
|
||||||
primary: "html5",
|
primary: "html5",
|
||||||
autostart: false,
|
autostart: this.props.config ? this.props.config.autostartVideo : false,
|
||||||
|
repeat: repeat,
|
||||||
playbackRateControls: true,
|
playbackRateControls: true,
|
||||||
playbackRates: [0.75, 1, 1.5, 2, 3, 4],
|
playbackRates: [0.75, 1, 1.5, 2, 3, 4],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private makeVideoJSConfig(scene: GQL.SceneDataFragment) {
|
||||||
|
if (!scene.paths.stream) { return {}; }
|
||||||
|
|
||||||
|
let repeat = this.shouldRepeat(scene);
|
||||||
|
|
||||||
|
return {
|
||||||
|
autoplay: this.props.config ? this.props.config.autostartVideo : false,
|
||||||
|
loop: repeat,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private onReady() {
|
private onReady() {
|
||||||
this.player = SceneHelpers.getPlayer();
|
this.player = SceneHelpers.getPlayer();
|
||||||
if (this.props.timestamp > 0) {
|
if (this.props.timestamp > 0) {
|
||||||
@@ -252,3 +283,9 @@ export class ScenePlayer extends React.Component<IScenePlayerProps, IScenePlayer
|
|||||||
this.player.pause();
|
this.player.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ScenePlayer: FunctionComponent<IScenePlayerProps> = (props: IScenePlayerProps) => {
|
||||||
|
const config = StashService.useConfiguration();
|
||||||
|
|
||||||
|
return <ScenePlayerImpl {...props} config={config.data && config.data.configuration ? config.data.configuration.interface : undefined}/>
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import _ from "lodash";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
interface IInterfaceWallConfig {
|
interface IInterfaceWallConfig {
|
||||||
textContainerEnabled: boolean;
|
|
||||||
soundEnabled: boolean;
|
|
||||||
}
|
}
|
||||||
export interface IInterfaceConfig {
|
export interface IInterfaceConfig {
|
||||||
wall: IInterfaceWallConfig;
|
wall: IInterfaceWallConfig;
|
||||||
@@ -25,8 +23,7 @@ export function useInterfaceLocalForage(): ILocalForage<IInterfaceConfig | undef
|
|||||||
if (result.data === undefined) {
|
if (result.data === undefined) {
|
||||||
result.setData({
|
result.setData({
|
||||||
wall: {
|
wall: {
|
||||||
textContainerEnabled: true,
|
// nothing here currently
|
||||||
soundEnabled: true,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { useInterfaceLocalForage } from "./LocalForage";
|
import { StashService } from "../core/StashService";
|
||||||
|
|
||||||
export interface IVideoHoverHookData {
|
export interface IVideoHoverHookData {
|
||||||
videoEl: React.RefObject<HTMLVideoElement>;
|
videoEl: React.RefObject<HTMLVideoElement>;
|
||||||
@@ -18,8 +18,8 @@ export class VideoHoverHook {
|
|||||||
const isPlaying = useRef<boolean>(false);
|
const isPlaying = useRef<boolean>(false);
|
||||||
const isHovering = useRef<boolean>(false);
|
const isHovering = useRef<boolean>(false);
|
||||||
|
|
||||||
const interfaceSettings = useInterfaceLocalForage();
|
const config = StashService.useConfiguration();
|
||||||
const soundEnabled = !!interfaceSettings.data ? interfaceSettings.data.wall.soundEnabled : true;
|
const soundEnabled = !!config.data && !!config.data.configuration ? config.data.configuration.interface.soundOnPreview : true;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const videoTag = videoEl.current;
|
const videoTag = videoEl.current;
|
||||||
|
|||||||
Reference in New Issue
Block a user