mirror of
https://github.com/stashapp/stash.git
synced 2025-12-15 21:03:22 +01:00
Add Play random button to scenes and scene markers page (#255)
* Add play random button for scenes * Add play random to scene markers
This commit is contained in:
parent
c66d9fcc28
commit
bb164f1895
7 changed files with 120 additions and 7 deletions
|
|
@ -1,8 +1,6 @@
|
|||
import {
|
||||
AnchorButton,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
ControlGroup,
|
||||
HTMLSelect,
|
||||
InputGroup,
|
||||
Menu,
|
||||
|
|
@ -13,12 +11,17 @@ import {
|
|||
Slider,
|
||||
} from "@blueprintjs/core";
|
||||
import { debounce } from "lodash";
|
||||
import React, { FunctionComponent, SyntheticEvent, useEffect, useRef, useState } from "react";
|
||||
import React, { FunctionComponent, SyntheticEvent, useEffect, useState } from "react";
|
||||
import { Criterion } from "../../models/list-filter/criteria/criterion";
|
||||
import { ListFilterModel } from "../../models/list-filter/filter";
|
||||
import { DisplayMode } from "../../models/list-filter/types";
|
||||
import { AddFilter } from "./AddFilter";
|
||||
|
||||
interface IListFilterOperation {
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
interface IListFilterProps {
|
||||
onChangePageSize: (pageSize: number) => void;
|
||||
onChangeQuery: (query: string) => void;
|
||||
|
|
@ -31,6 +34,7 @@ interface IListFilterProps {
|
|||
onChangeZoom?: (zoomIndex: number) => void;
|
||||
onSelectAll?: () => void;
|
||||
onSelectNone?: () => void;
|
||||
otherOperations?: IListFilterOperation[];
|
||||
filter: ListFilterModel;
|
||||
}
|
||||
|
||||
|
|
@ -169,6 +173,13 @@ export const ListFilter: FunctionComponent<IListFilterProps> = (props: IListFilt
|
|||
let options = [];
|
||||
options.push(renderSelectAll());
|
||||
options.push(renderSelectNone());
|
||||
|
||||
if (props.otherOperations) {
|
||||
props.otherOperations.forEach((o) => {
|
||||
options.push(<MenuItem onClick={o.onClick} text={o.text} />);
|
||||
});
|
||||
}
|
||||
|
||||
options = options.filter((o) => !!o);
|
||||
|
||||
let menuItems = options as JSX.Element[];
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ interface ISceneProps extends IBaseProps {}
|
|||
|
||||
export const Scene: FunctionComponent<ISceneProps> = (props: ISceneProps) => {
|
||||
const [timestamp, setTimestamp] = useState<number>(0);
|
||||
const [autoplay, setAutoplay] = useState<boolean>(false);
|
||||
const [scene, setScene] = useState<Partial<GQL.SceneDataFragment>>({});
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { data, error, loading } = StashService.useFindScene(props.match.params.id);
|
||||
|
|
@ -37,6 +38,9 @@ export const Scene: FunctionComponent<ISceneProps> = (props: ISceneProps) => {
|
|||
const newTimestamp = parseInt(queryParams.t, 10);
|
||||
setTimestamp(newTimestamp);
|
||||
}
|
||||
if (queryParams.autoplay && typeof queryParams.autoplay === "string") {
|
||||
setAutoplay(queryParams.autoplay === "true");
|
||||
}
|
||||
});
|
||||
|
||||
function onClickMarker(marker: GQL.SceneMarkerDataFragment) {
|
||||
|
|
@ -52,7 +56,7 @@ export const Scene: FunctionComponent<ISceneProps> = (props: ISceneProps) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<ScenePlayer scene={modifiedScene} timestamp={timestamp} />
|
||||
<ScenePlayer scene={modifiedScene} timestamp={timestamp} autoplay={autoplay}/>
|
||||
<Card id="details-container">
|
||||
<Tabs
|
||||
renderActiveTabPanelOnly={true}
|
||||
|
|
|
|||
|
|
@ -10,18 +10,45 @@ import { WallPanel } from "../Wall/WallPanel";
|
|||
import { SceneCard } from "./SceneCard";
|
||||
import { SceneListTable } from "./SceneListTable";
|
||||
import { SceneSelectedOptions } from "./SceneSelectedOptions";
|
||||
import { StashService } from "../../core/StashService";
|
||||
|
||||
interface ISceneListProps extends IBaseProps {}
|
||||
|
||||
export const SceneList: FunctionComponent<ISceneListProps> = (props: ISceneListProps) => {
|
||||
const otherOperations = [
|
||||
{
|
||||
text: "Play Random",
|
||||
onClick: playRandom,
|
||||
}
|
||||
];
|
||||
|
||||
const listData = ListHook.useList({
|
||||
filterMode: FilterMode.Scenes,
|
||||
props,
|
||||
zoomable: true,
|
||||
otherOperations: otherOperations,
|
||||
renderContent,
|
||||
renderSelectedOptions
|
||||
});
|
||||
|
||||
async function playRandom(result: QueryHookResult<FindScenesQuery, FindScenesVariables>, filter: ListFilterModel, selectedIds: Set<string>) {
|
||||
// query for a random scene
|
||||
if (result.data && result.data.findScenes) {
|
||||
let count = result.data.findScenes.count;
|
||||
|
||||
let index = Math.floor(Math.random() * count);
|
||||
let filterCopy = _.cloneDeep(filter);
|
||||
filterCopy.itemsPerPage = 1;
|
||||
filterCopy.currentPage = index + 1;
|
||||
const singleResult = await StashService.queryFindScenes(filterCopy);
|
||||
if (singleResult && singleResult.data && singleResult.data.findScenes && singleResult.data.findScenes.scenes.length === 1) {
|
||||
let id = singleResult!.data!.findScenes!.scenes[0].id;
|
||||
// navigate to the scene player page
|
||||
props.history.push("/scenes/" + id + "?autoplay=true");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderSelectedOptions(result: QueryHookResult<FindScenesQuery, FindScenesVariables>, selectedIds: Set<string>) {
|
||||
// find the selected items from the ids
|
||||
if (!result.data || !result.data.findScenes) { return undefined; }
|
||||
|
|
|
|||
|
|
@ -7,16 +7,44 @@ import { IBaseProps } from "../../models/base-props";
|
|||
import { ListFilterModel } from "../../models/list-filter/filter";
|
||||
import { DisplayMode, FilterMode } from "../../models/list-filter/types";
|
||||
import { WallPanel } from "../Wall/WallPanel";
|
||||
import { StashService } from "../../core/StashService";
|
||||
import { NavigationUtils } from "../../utils/navigation";
|
||||
|
||||
interface IProps extends IBaseProps {}
|
||||
|
||||
export const SceneMarkerList: FunctionComponent<IProps> = (props: IProps) => {
|
||||
const otherOperations = [
|
||||
{
|
||||
text: "Play Random",
|
||||
onClick: playRandom,
|
||||
}
|
||||
];
|
||||
|
||||
const listData = ListHook.useList({
|
||||
filterMode: FilterMode.SceneMarkers,
|
||||
otherOperations: otherOperations,
|
||||
props,
|
||||
renderContent,
|
||||
});
|
||||
|
||||
async function playRandom(result: QueryHookResult<FindSceneMarkersQuery, FindSceneMarkersVariables>, filter: ListFilterModel, selectedIds: Set<string>) {
|
||||
// query for a random scene
|
||||
if (result.data && result.data.findSceneMarkers) {
|
||||
let count = result.data.findSceneMarkers.count;
|
||||
|
||||
let index = Math.floor(Math.random() * count);
|
||||
let filterCopy = _.cloneDeep(filter);
|
||||
filterCopy.itemsPerPage = 1;
|
||||
filterCopy.currentPage = index + 1;
|
||||
const singleResult = await StashService.queryFindSceneMarkers(filterCopy);
|
||||
if (singleResult && singleResult.data && singleResult.data.findSceneMarkers && singleResult.data.findSceneMarkers.scene_markers.length === 1) {
|
||||
// navigate to the scene player page
|
||||
let url = NavigationUtils.makeSceneMarkerUrl(singleResult!.data!.findSceneMarkers!.scene_markers[0])
|
||||
props.history.push(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderContent(
|
||||
result: QueryHookResult<FindSceneMarkersQuery, FindSceneMarkersVariables>,
|
||||
filter: ListFilterModel,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { StashService } from "../../../core/StashService";
|
|||
interface IScenePlayerProps {
|
||||
scene: GQL.SceneDataFragment;
|
||||
timestamp: number;
|
||||
autoplay?: boolean;
|
||||
onReady?: any;
|
||||
onSeeked?: any;
|
||||
onTime?: any;
|
||||
|
|
@ -235,7 +236,7 @@ export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePl
|
|||
},
|
||||
cast: {},
|
||||
primary: "html5",
|
||||
autostart: this.props.config ? this.props.config.autostartVideo : false,
|
||||
autostart: this.props.autoplay || (this.props.config ? this.props.config.autostartVideo : false),
|
||||
repeat: repeat,
|
||||
playbackRateControls: true,
|
||||
playbackRates: [0.75, 1, 1.5, 2, 3, 4],
|
||||
|
|
@ -248,7 +249,7 @@ export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePl
|
|||
let repeat = this.shouldRepeat(scene);
|
||||
|
||||
return {
|
||||
autoplay: this.props.config ? this.props.config.autostartVideo : false,
|
||||
autoplay: this.props.autoplay || (this.props.config ? this.props.config.autostartVideo : false),
|
||||
loop: repeat,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,19 @@ export class StashService {
|
|||
});
|
||||
}
|
||||
|
||||
public static queryFindScenes(filter: ListFilterModel) {
|
||||
let sceneFilter = {};
|
||||
sceneFilter = filter.makeSceneFilter();
|
||||
|
||||
return StashService.client.query<GQL.FindScenesQuery>({
|
||||
query: GQL.FindScenesDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
scene_filter: sceneFilter,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static useFindSceneMarkers(filter: ListFilterModel) {
|
||||
let sceneMarkerFilter = {};
|
||||
// if (!!filter && filter.criteriaFilterOpen) {
|
||||
|
|
@ -129,6 +142,19 @@ export class StashService {
|
|||
});
|
||||
}
|
||||
|
||||
public static queryFindSceneMarkers(filter: ListFilterModel) {
|
||||
let sceneMarkerFilter = {};
|
||||
sceneMarkerFilter = filter.makeSceneMarkerFilter();
|
||||
|
||||
return StashService.client.query<GQL.FindSceneMarkersQuery>({
|
||||
query: GQL.FindSceneMarkersDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
scene_marker_filter: sceneMarkerFilter,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static useFindStudios(filter: ListFilterModel) {
|
||||
return GQL.useFindStudios({
|
||||
variables: {
|
||||
|
|
|
|||
|
|
@ -18,10 +18,16 @@ export interface IListHookData {
|
|||
onSelectChange: (id: string, selected : boolean, shiftKey: boolean) => void;
|
||||
}
|
||||
|
||||
interface IListHookOperation {
|
||||
text: string;
|
||||
onClick: (result: QueryHookResult<any, any>, filter: ListFilterModel, selectedIds: Set<string>) => void;
|
||||
}
|
||||
|
||||
export interface IListHookOptions {
|
||||
filterMode: FilterMode;
|
||||
props: IBaseProps;
|
||||
zoomable?: boolean
|
||||
zoomable?: boolean;
|
||||
otherOperations?: IListHookOperation[];
|
||||
renderContent: (result: QueryHookResult<any, any>, filter: ListFilterModel, selectedIds: Set<string>, zoomIndex: number) => JSX.Element | undefined;
|
||||
renderSelectedOptions?: (result: QueryHookResult<any, any>, selectedIds: Set<string>) => JSX.Element | undefined;
|
||||
}
|
||||
|
|
@ -260,6 +266,15 @@ export class ListHook {
|
|||
setZoomIndex(newZoomIndex);
|
||||
}
|
||||
|
||||
const otherOperations = options.otherOperations ? options.otherOperations.map((o) => {
|
||||
return {
|
||||
text: o.text,
|
||||
onClick: () => {
|
||||
o.onClick(result, filter, selectedIds);
|
||||
}
|
||||
}
|
||||
}) : undefined;
|
||||
|
||||
const template = (
|
||||
<div>
|
||||
<ListFilter
|
||||
|
|
@ -274,6 +289,7 @@ export class ListHook {
|
|||
onSelectNone={onSelectNone}
|
||||
zoomIndex={options.zoomable ? zoomIndex : undefined}
|
||||
onChangeZoom={options.zoomable ? onChangeZoom : undefined}
|
||||
otherOperations={otherOperations}
|
||||
filter={filter}
|
||||
/>
|
||||
{options.renderSelectedOptions && selectedIds.size > 0 ? options.renderSelectedOptions(result, selectedIds) : undefined}
|
||||
|
|
|
|||
Loading…
Reference in a new issue