diff --git a/graphql/documents/data/config.graphql b/graphql/documents/data/config.graphql index 67f8c60c6..4964ab3cd 100644 --- a/graphql/documents/data/config.graphql +++ b/graphql/documents/data/config.graphql @@ -54,6 +54,8 @@ fragment ConfigInterfaceData on ConfigInterfaceResult { maximumLoopDuration noBrowser autostartVideo + autostartVideoOnPlaySelected + continuePlaylistDefault showStudioAsText css cssEnabled diff --git a/graphql/schema/types/config.graphql b/graphql/schema/types/config.graphql index 213b253dc..6e8699a10 100644 --- a/graphql/schema/types/config.graphql +++ b/graphql/schema/types/config.graphql @@ -197,27 +197,40 @@ input ConfigDisableDropdownCreateInput { input ConfigInterfaceInput { """Ordered list of items that should be shown in the menu""" menuItems: [String!] + """Enable sound on mouseover previews""" soundOnPreview: Boolean + """Show title and tags in wall view""" wallShowTitle: Boolean """Wall playback type""" wallPlayback: String + """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 + """If true, video will autostart when loading from play random or play selected""" + autostartVideoOnPlaySelected: Boolean + """If true, next scene in playlist will be played at video end by default""" + continuePlaylistDefault: Boolean + """If true, studio overlays will be shown as text instead of logo images""" showStudioAsText: Boolean + """Custom CSS""" css: String cssEnabled: Boolean + """Interface language""" language: String + """Slideshow Delay""" slideshowDelay: Int + """Set to true to disable creating new objects via the dropdown menus""" disableDropdownCreate: ConfigDisableDropdownCreateInput + """Handy Connection Key""" handyKey: String """Funscript Time Offset""" @@ -235,29 +248,42 @@ type ConfigDisableDropdownCreate { type ConfigInterfaceResult { """Ordered list of items that should be shown in the menu""" menuItems: [String!] + """Enable sound on mouseover previews""" soundOnPreview: Boolean + """Show title and tags in wall view""" wallShowTitle: Boolean """Wall playback type""" wallPlayback: String + """Maximum duration (in seconds) in which a scene video will loop in the scene player""" maximumLoopDuration: Int """"True if we should not auto-open a browser window on startup""" noBrowser: Boolean """If true, video will autostart on load in the scene player""" autostartVideo: Boolean + """If true, video will autostart when loading from play random or play selected""" + autostartVideoOnPlaySelected: Boolean + """If true, next scene in playlist will be played at video end by default""" + continuePlaylistDefault: Boolean + """If true, studio overlays will be shown as text instead of logo images""" showStudioAsText: Boolean + """Custom CSS""" css: String cssEnabled: Boolean + """Interface language""" language: String + """Slideshow Delay""" slideshowDelay: Int + """Fields are true if creating via dropdown menus are disabled""" disabledDropdownCreate: ConfigDisableDropdownCreate! + """Handy Connection Key""" handyKey: String """Funscript Time Offset""" diff --git a/pkg/api/resolver_mutation_configure.go b/pkg/api/resolver_mutation_configure.go index 2071f531d..ee038ae77 100644 --- a/pkg/api/resolver_mutation_configure.go +++ b/pkg/api/resolver_mutation_configure.go @@ -251,6 +251,8 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models. setBool(config.AutostartVideo, input.AutostartVideo) setBool(config.ShowStudioAsText, input.ShowStudioAsText) + setBool(config.AutostartVideoOnPlaySelected, input.AutostartVideoOnPlaySelected) + setBool(config.ContinuePlaylistDefault, input.ContinuePlaylistDefault) if input.Language != nil { c.Set(config.Language, *input.Language) diff --git a/pkg/api/resolver_query_configuration.go b/pkg/api/resolver_query_configuration.go index e5777ef1b..413aba88e 100644 --- a/pkg/api/resolver_query_configuration.go +++ b/pkg/api/resolver_query_configuration.go @@ -111,6 +111,8 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult { noBrowser := config.GetNoBrowserFlag() maximumLoopDuration := config.GetMaximumLoopDuration() autostartVideo := config.GetAutostartVideo() + autostartVideoOnPlaySelected := config.GetAutostartVideoOnPlaySelected() + continuePlaylistDefault := config.GetContinuePlaylistDefault() showStudioAsText := config.GetShowStudioAsText() css := config.GetCSS() cssEnabled := config.GetCSSEnabled() @@ -120,21 +122,23 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult { scriptOffset := config.GetFunscriptOffset() return &models.ConfigInterfaceResult{ - MenuItems: menuItems, - SoundOnPreview: &soundOnPreview, - WallShowTitle: &wallShowTitle, - WallPlayback: &wallPlayback, - MaximumLoopDuration: &maximumLoopDuration, - NoBrowser: &noBrowser, - AutostartVideo: &autostartVideo, - ShowStudioAsText: &showStudioAsText, - CSS: &css, - CSSEnabled: &cssEnabled, - Language: &language, - SlideshowDelay: &slideshowDelay, - DisabledDropdownCreate: config.GetDisableDropdownCreate(), - HandyKey: &handyKey, - FunscriptOffset: &scriptOffset, + MenuItems: menuItems, + SoundOnPreview: &soundOnPreview, + WallShowTitle: &wallShowTitle, + WallPlayback: &wallPlayback, + MaximumLoopDuration: &maximumLoopDuration, + NoBrowser: &noBrowser, + AutostartVideo: &autostartVideo, + ShowStudioAsText: &showStudioAsText, + AutostartVideoOnPlaySelected: &autostartVideoOnPlaySelected, + ContinuePlaylistDefault: &continuePlaylistDefault, + CSS: &css, + CSSEnabled: &cssEnabled, + Language: &language, + SlideshowDelay: &slideshowDelay, + DisabledDropdownCreate: config.GetDisableDropdownCreate(), + HandyKey: &handyKey, + FunscriptOffset: &scriptOffset, } } diff --git a/pkg/manager/config/config.go b/pkg/manager/config/config.go index 4105c22da..27dd82ad7 100644 --- a/pkg/manager/config/config.go +++ b/pkg/manager/config/config.go @@ -130,6 +130,8 @@ const WallShowTitle = "wall_show_title" const CustomPerformerImageLocation = "custom_performer_image_location" const MaximumLoopDuration = "maximum_loop_duration" const AutostartVideo = "autostart_video" +const AutostartVideoOnPlaySelected = "autostart_video_on_play_selected" +const ContinuePlaylistDefault = "continue_playlist_default" const ShowStudioAsText = "show_studio_as_text" const CSSEnabled = "cssEnabled" const WallPlayback = "wall_playback" @@ -808,6 +810,20 @@ func (i *Instance) GetAutostartVideo() bool { return viper.GetBool(AutostartVideo) } +func (i *Instance) GetAutostartVideoOnPlaySelected() bool { + i.Lock() + defer i.Unlock() + viper.SetDefault(AutostartVideoOnPlaySelected, true) + return viper.GetBool(AutostartVideoOnPlaySelected) +} + +func (i *Instance) GetContinuePlaylistDefault() bool { + i.Lock() + defer i.Unlock() + viper.SetDefault(ContinuePlaylistDefault, false) + return viper.GetBool(ContinuePlaylistDefault) +} + func (i *Instance) GetShowStudioAsText() bool { i.Lock() defer i.Unlock() diff --git a/pkg/manager/config/config_concurrency_test.go b/pkg/manager/config/config_concurrency_test.go index 7447a581a..8558f0214 100644 --- a/pkg/manager/config/config_concurrency_test.go +++ b/pkg/manager/config/config_concurrency_test.go @@ -94,6 +94,8 @@ func TestConcurrentConfigAccess(t *testing.T) { i.Set(MaxUploadSize, i.GetMaxUploadSize()) i.Set(FunscriptOffset, i.GetFunscriptOffset()) i.Set(DefaultIdentifySettings, i.GetDefaultIdentifySettings()) + i.Set(AutostartVideoOnPlaySelected, i.GetAutostartVideoOnPlaySelected()) + i.Set(ContinuePlaylistDefault, i.GetContinuePlaylistDefault()) } wg.Done() }(k) diff --git a/ui/v2.5/src/components/Changelog/versions/v0110.md b/ui/v2.5/src/components/Changelog/versions/v0110.md index a46e32b00..8fc4d2011 100644 --- a/ui/v2.5/src/components/Changelog/versions/v0110.md +++ b/ui/v2.5/src/components/Changelog/versions/v0110.md @@ -1,4 +1,5 @@ ### ✨ New Features +* Add options to auto-start videos when playing from selection and continue to scene playlists. ([#1921](https://github.com/stashapp/stash/pull/1921)) * Support is (not) null for multi-relational filter criteria. ([#1785](https://github.com/stashapp/stash/pull/1785)) * Optionally open browser on startup (enabled by default for new systems). ([#1832](https://github.com/stashapp/stash/pull/1832)) * Support setting defaults for Delete File and Delete Generated Files in the Interface Settings. ([#1852](https://github.com/stashapp/stash/pull/1852)) diff --git a/ui/v2.5/src/components/Galleries/GalleryList.tsx b/ui/v2.5/src/components/Galleries/GalleryList.tsx index e56f728fa..cb240f13d 100644 --- a/ui/v2.5/src/components/Galleries/GalleryList.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryList.tsx @@ -88,13 +88,8 @@ export const GalleryList: React.FC = ({ filterCopy.itemsPerPage = 1; filterCopy.currentPage = index + 1; const singleResult = await queryFindGalleries(filterCopy); - if ( - singleResult && - singleResult.data && - singleResult.data.findGalleries && - singleResult.data.findGalleries.galleries.length === 1 - ) { - const { id } = singleResult!.data!.findGalleries!.galleries[0]; + if (singleResult.data.findGalleries.galleries.length === 1) { + const { id } = singleResult.data.findGalleries.galleries[0]; // navigate to the image player page history.push(`/galleries/${id}`); } diff --git a/ui/v2.5/src/components/Scenes/SceneCard.tsx b/ui/v2.5/src/components/Scenes/SceneCard.tsx index 15cc58585..5aa4e4189 100644 --- a/ui/v2.5/src/components/Scenes/SceneCard.tsx +++ b/ui/v2.5/src/components/Scenes/SceneCard.tsx @@ -305,8 +305,13 @@ export const SceneCard: React.FC = ( } } + const cont = configuration?.interface.continuePlaylistDefault ?? false; + const sceneLink = props.queue - ? props.queue.makeLink(props.scene.id, { sceneIndex: props.index }) + ? props.queue.makeLink(props.scene.id, { + sceneIndex: props.index, + continue: cont, + }) : `/scenes/${props.scene.id}`; return ( diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/QueueViewer.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/QueueViewer.tsx index 8ecf615cd..e47090552 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/QueueViewer.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/QueueViewer.tsx @@ -3,14 +3,17 @@ import { Link } from "react-router-dom"; import cx from "classnames"; import * as GQL from "src/core/generated-graphql"; import { TextUtils } from "src/utils"; -import { Button, Spinner } from "react-bootstrap"; +import { Button, Form, Spinner } from "react-bootstrap"; import { Icon } from "src/components/Shared"; +import { useIntl } from "react-intl"; export interface IPlaylistViewer { scenes?: GQL.SlimSceneDataFragment[]; currentID?: string; start?: number; + continue?: boolean; hasMoreScenes: boolean; + setContinue: (v: boolean) => void; onSceneClicked: (id: string) => void; onNext: () => void; onPrevious: () => void; @@ -23,7 +26,9 @@ export const QueueViewer: React.FC = ({ scenes, currentID, start, + continue: continuePlaylist = false, hasMoreScenes, + setContinue, onNext, onPrevious, onRandom, @@ -31,6 +36,7 @@ export const QueueViewer: React.FC = ({ onMoreScenes, onLessScenes, }) => { + const intl = useIntl(); const [lessLoading, setLessLoading] = useState(false); const [moreLoading, setMoreLoading] = useState(false); @@ -91,6 +97,17 @@ export const QueueViewer: React.FC = ({ return (
+
+ { + setContinue(!continuePlaylist); + }} + /> +
{(currentIndex ?? 0) > 0 ? (