mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Replace JW Player with video.js (#2100)
* Replace JW Player with video.js * Move HLS stream to bottom of list HLS doesn't work very well on non-ios devices. Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,6 @@ import React, { useEffect, useState, useMemo, useContext } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { useParams, useLocation, useHistory, Link } from "react-router-dom";
|
||||
import { Helmet } from "react-helmet";
|
||||
import Mousetrap from "mousetrap";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import {
|
||||
mutateMetadataScan,
|
||||
@@ -12,19 +11,19 @@ import {
|
||||
useSceneIncrementO,
|
||||
useSceneDecrementO,
|
||||
useSceneResetO,
|
||||
useSceneStreams,
|
||||
useSceneGenerateScreenshot,
|
||||
useSceneUpdate,
|
||||
queryFindScenes,
|
||||
queryFindScenesByID,
|
||||
} from "src/core/StashService";
|
||||
import { GalleryViewer } from "src/components/Galleries/GalleryViewer";
|
||||
import { ErrorMessage, LoadingIndicator, Icon } from "src/components/Shared";
|
||||
import { Icon } from "src/components/Shared";
|
||||
import { useToast } from "src/hooks";
|
||||
import { ScenePlayer } from "src/components/ScenePlayer";
|
||||
import { TextUtils, JWUtils } from "src/utils";
|
||||
import { SubmitStashBoxDraft } from "src/components/Dialogs/SubmitDraft";
|
||||
import { ScenePlayer, getPlayerPosition } from "src/components/ScenePlayer";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { TextUtils } from "src/utils";
|
||||
import Mousetrap from "mousetrap";
|
||||
import { SceneQueue } from "src/models/sceneQueue";
|
||||
import { QueueViewer } from "./QueueViewer";
|
||||
import { SceneMarkersPanel } from "./SceneMarkersPanel";
|
||||
@@ -44,32 +43,50 @@ import { ConfigurationContext } from "src/hooks/Config";
|
||||
interface IProps {
|
||||
scene: GQL.SceneDataFragment;
|
||||
refetch: () => void;
|
||||
setTimestamp: (num: number) => void;
|
||||
queueScenes: GQL.SceneDataFragment[];
|
||||
onQueueNext: () => void;
|
||||
onQueuePrevious: () => void;
|
||||
onQueueRandom: () => void;
|
||||
continuePlaylist: boolean;
|
||||
playScene: (sceneID: string, page?: number) => void;
|
||||
queueHasMoreScenes: () => boolean;
|
||||
onQueueMoreScenes: () => void;
|
||||
onQueueLessScenes: () => void;
|
||||
queueStart: number;
|
||||
collapsed: boolean;
|
||||
setCollapsed: (state: boolean) => void;
|
||||
setContinuePlaylist: (value: boolean) => void;
|
||||
}
|
||||
|
||||
const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
const location = useLocation();
|
||||
const ScenePage: React.FC<IProps> = ({
|
||||
scene,
|
||||
refetch,
|
||||
setTimestamp,
|
||||
queueScenes,
|
||||
onQueueNext,
|
||||
onQueuePrevious,
|
||||
onQueueRandom,
|
||||
continuePlaylist,
|
||||
playScene,
|
||||
queueHasMoreScenes,
|
||||
onQueueMoreScenes,
|
||||
onQueueLessScenes,
|
||||
queueStart,
|
||||
collapsed,
|
||||
setCollapsed,
|
||||
setContinuePlaylist,
|
||||
}) => {
|
||||
const history = useHistory();
|
||||
const Toast = useToast();
|
||||
const intl = useIntl();
|
||||
const [updateScene] = useSceneUpdate();
|
||||
const [generateScreenshot] = useSceneGenerateScreenshot();
|
||||
const [timestamp, setTimestamp] = useState<number>(getInitialTimestamp());
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
const { configuration } = useContext(ConfigurationContext);
|
||||
|
||||
const [showScrubber, setShowScrubber] = useState(
|
||||
configuration?.interface.showScrubber ?? true
|
||||
);
|
||||
const [showDraftModal, setShowDraftModal] = useState(false);
|
||||
const boxes = configuration?.general?.stashBoxes ?? [];
|
||||
|
||||
const {
|
||||
data: sceneStreams,
|
||||
error: streamableError,
|
||||
loading: streamableLoading,
|
||||
} = useSceneStreams(scene.id);
|
||||
|
||||
const [incrementO] = useSceneIncrementO(scene.id);
|
||||
const [decrementO] = useSceneDecrementO(scene.id);
|
||||
const [resetO] = useSceneResetO(scene.id);
|
||||
@@ -81,75 +98,48 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
||||
const [isGenerateDialogOpen, setIsGenerateDialogOpen] = useState(false);
|
||||
|
||||
const [sceneQueue, setSceneQueue] = useState<SceneQueue>(new SceneQueue());
|
||||
const [queueScenes, setQueueScenes] = useState<GQL.SlimSceneDataFragment[]>(
|
||||
[]
|
||||
);
|
||||
|
||||
const [queueTotal, setQueueTotal] = useState(0);
|
||||
const [queueStart, setQueueStart] = useState(1);
|
||||
const [continuePlaylist, setContinuePlaylist] = useState(false);
|
||||
|
||||
const [rerenderPlayer, setRerenderPlayer] = useState(false);
|
||||
|
||||
const queryParams = useMemo(() => queryString.parse(location.search), [
|
||||
location.search,
|
||||
]);
|
||||
const autoplay = queryParams?.autoplay === "true";
|
||||
const currentQueueIndex = queueScenes.findIndex((s) => s.id === scene.id);
|
||||
|
||||
async function getQueueFilterScenes(filter: ListFilterModel) {
|
||||
const query = await queryFindScenes(filter);
|
||||
const { scenes, count } = query.data.findScenes;
|
||||
setQueueScenes(scenes);
|
||||
setQueueTotal(count);
|
||||
setQueueStart((filter.currentPage - 1) * filter.itemsPerPage + 1);
|
||||
}
|
||||
|
||||
async function getQueueScenes(sceneIDs: number[]) {
|
||||
const query = await queryFindScenesByID(sceneIDs);
|
||||
const { scenes, count } = query.data.findScenes;
|
||||
setQueueScenes(scenes);
|
||||
setQueueTotal(count);
|
||||
setQueueStart(1);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setContinuePlaylist(queryParams?.continue === "true");
|
||||
}, [queryParams]);
|
||||
|
||||
// HACK - jwplayer doesn't handle re-rendering when scene changes, so force
|
||||
// a rerender by not drawing it
|
||||
useEffect(() => {
|
||||
if (rerenderPlayer) {
|
||||
setRerenderPlayer(false);
|
||||
const onIncrementClick = async () => {
|
||||
try {
|
||||
await incrementO();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
}
|
||||
}, [rerenderPlayer]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setRerenderPlayer(true);
|
||||
}, [scene.id]);
|
||||
|
||||
useEffect(() => {
|
||||
setSceneQueue(SceneQueue.fromQueryParameters(location.search));
|
||||
}, [location.search]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sceneQueue.query) {
|
||||
getQueueFilterScenes(sceneQueue.query);
|
||||
} else if (sceneQueue.sceneIDs) {
|
||||
getQueueScenes(sceneQueue.sceneIDs);
|
||||
const onDecrementClick = async () => {
|
||||
try {
|
||||
await decrementO();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
}
|
||||
}, [sceneQueue]);
|
||||
};
|
||||
|
||||
function getInitialTimestamp() {
|
||||
const params = queryString.parse(location.search);
|
||||
const initialTimestamp = params?.t ?? "0";
|
||||
return Number.parseInt(
|
||||
Array.isArray(initialTimestamp) ? initialTimestamp[0] : initialTimestamp,
|
||||
10
|
||||
);
|
||||
}
|
||||
// set up hotkeys
|
||||
useEffect(() => {
|
||||
Mousetrap.bind("a", () => setActiveTabKey("scene-details-panel"));
|
||||
Mousetrap.bind("q", () => setActiveTabKey("scene-queue-panel"));
|
||||
Mousetrap.bind("e", () => setActiveTabKey("scene-edit-panel"));
|
||||
Mousetrap.bind("k", () => setActiveTabKey("scene-markers-panel"));
|
||||
Mousetrap.bind("i", () => setActiveTabKey("scene-file-info-panel"));
|
||||
Mousetrap.bind("o", () => onIncrementClick());
|
||||
Mousetrap.bind("p n", () => onQueueNext());
|
||||
Mousetrap.bind("p p", () => onQueuePrevious());
|
||||
Mousetrap.bind("p r", () => onQueueRandom());
|
||||
Mousetrap.bind(",", () => setCollapsed(!collapsed));
|
||||
|
||||
return () => {
|
||||
Mousetrap.unbind("a");
|
||||
Mousetrap.unbind("q");
|
||||
Mousetrap.unbind("e");
|
||||
Mousetrap.unbind("k");
|
||||
Mousetrap.unbind("i");
|
||||
Mousetrap.unbind("o");
|
||||
Mousetrap.unbind("p n");
|
||||
Mousetrap.unbind("p p");
|
||||
Mousetrap.unbind("p r");
|
||||
Mousetrap.unbind(",");
|
||||
};
|
||||
});
|
||||
|
||||
const onOrganizedClick = async () => {
|
||||
try {
|
||||
@@ -169,22 +159,6 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const onIncrementClick = async () => {
|
||||
try {
|
||||
await incrementO();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const onDecrementClick = async () => {
|
||||
try {
|
||||
await decrementO();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const onResetClick = async () => {
|
||||
try {
|
||||
await resetO();
|
||||
@@ -227,93 +201,6 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
});
|
||||
}
|
||||
|
||||
async function onQueueLessScenes() {
|
||||
if (!sceneQueue.query || queueStart <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterCopy = sceneQueue.query.clone();
|
||||
const newStart = queueStart - filterCopy.itemsPerPage;
|
||||
filterCopy.currentPage = Math.ceil(newStart / filterCopy.itemsPerPage);
|
||||
const query = await queryFindScenes(filterCopy);
|
||||
const { scenes } = query.data.findScenes;
|
||||
|
||||
// prepend scenes to scene list
|
||||
const newScenes = scenes.concat(queueScenes);
|
||||
setQueueScenes(newScenes);
|
||||
setQueueStart(newStart);
|
||||
}
|
||||
|
||||
function queueHasMoreScenes() {
|
||||
return queueStart + queueScenes.length - 1 < queueTotal;
|
||||
}
|
||||
|
||||
async function onQueueMoreScenes() {
|
||||
if (!sceneQueue.query || !queueHasMoreScenes()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterCopy = sceneQueue.query.clone();
|
||||
const newStart = queueStart + queueScenes.length;
|
||||
filterCopy.currentPage = Math.ceil(newStart / filterCopy.itemsPerPage);
|
||||
const query = await queryFindScenes(filterCopy);
|
||||
const { scenes } = query.data.findScenes;
|
||||
|
||||
// append scenes to scene list
|
||||
const newScenes = scenes.concat(queueScenes);
|
||||
setQueueScenes(newScenes);
|
||||
// don't change queue start
|
||||
}
|
||||
|
||||
function playScene(sceneID: string, page?: number) {
|
||||
sceneQueue.playScene(history, sceneID, {
|
||||
newPage: page,
|
||||
autoPlay: true,
|
||||
continue: continuePlaylist,
|
||||
});
|
||||
}
|
||||
|
||||
function onQueueNext() {
|
||||
if (currentQueueIndex >= 0 && currentQueueIndex < queueScenes.length - 1) {
|
||||
playScene(queueScenes[currentQueueIndex + 1].id);
|
||||
}
|
||||
}
|
||||
|
||||
function onQueuePrevious() {
|
||||
if (currentQueueIndex > 0) {
|
||||
playScene(queueScenes[currentQueueIndex - 1].id);
|
||||
}
|
||||
}
|
||||
|
||||
async function onQueueRandom() {
|
||||
if (sceneQueue.query) {
|
||||
const { query } = sceneQueue;
|
||||
const pages = Math.ceil(queueTotal / query.itemsPerPage);
|
||||
const page = Math.floor(Math.random() * pages) + 1;
|
||||
const index = Math.floor(
|
||||
Math.random() * Math.min(query.itemsPerPage, queueTotal)
|
||||
);
|
||||
const filterCopy = sceneQueue.query.clone();
|
||||
filterCopy.currentPage = page;
|
||||
const queryResults = await queryFindScenes(filterCopy);
|
||||
if (queryResults.data.findScenes.scenes.length > index) {
|
||||
const { id: sceneID } = queryResults!.data!.findScenes!.scenes[index];
|
||||
// navigate to the image player page
|
||||
playScene(sceneID, page);
|
||||
}
|
||||
} else {
|
||||
const index = Math.floor(Math.random() * queueTotal);
|
||||
playScene(queueScenes[index].id);
|
||||
}
|
||||
}
|
||||
|
||||
function onComplete() {
|
||||
// load the next scene if we're autoplaying
|
||||
if (continuePlaylist) {
|
||||
onQueueNext();
|
||||
}
|
||||
}
|
||||
|
||||
function onDeleteDialogClosed(deleted: boolean) {
|
||||
setIsDeleteAlertOpen(false);
|
||||
if (deleted) {
|
||||
@@ -370,9 +257,7 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
<Dropdown.Item
|
||||
key="generate-screenshot"
|
||||
className="bg-secondary text-white"
|
||||
onClick={() =>
|
||||
onGenerateScreenshot(JWUtils.getPlayer().getPosition())
|
||||
}
|
||||
onClick={() => onGenerateScreenshot(getPlayerPosition())}
|
||||
>
|
||||
<FormattedMessage id="actions.generate_thumb_from_current" />
|
||||
</Dropdown.Item>
|
||||
@@ -502,7 +387,7 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
scenes={queueScenes}
|
||||
currentID={scene.id}
|
||||
continue={continuePlaylist}
|
||||
setContinue={(v) => setContinuePlaylist(v)}
|
||||
setContinue={setContinuePlaylist}
|
||||
onSceneClicked={(sceneID) => playScene(sceneID)}
|
||||
onNext={onQueueNext}
|
||||
onPrevious={onQueuePrevious}
|
||||
@@ -515,7 +400,7 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
</Tab.Pane>
|
||||
<Tab.Pane eventKey="scene-markers-panel">
|
||||
<SceneMarkersPanel
|
||||
scene={scene}
|
||||
sceneId={scene.id}
|
||||
onClickMarker={onClickMarker}
|
||||
isVisible={activeTabKey === "scene-markers-panel"}
|
||||
/>
|
||||
@@ -551,44 +436,12 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
</Tab.Container>
|
||||
);
|
||||
|
||||
// set up hotkeys
|
||||
useEffect(() => {
|
||||
Mousetrap.bind("a", () => setActiveTabKey("scene-details-panel"));
|
||||
Mousetrap.bind("q", () => setActiveTabKey("scene-queue-panel"));
|
||||
Mousetrap.bind("e", () => setActiveTabKey("scene-edit-panel"));
|
||||
Mousetrap.bind("k", () => setActiveTabKey("scene-markers-panel"));
|
||||
Mousetrap.bind("i", () => setActiveTabKey("scene-file-info-panel"));
|
||||
Mousetrap.bind("o", () => onIncrementClick());
|
||||
Mousetrap.bind("p n", () => onQueueNext());
|
||||
Mousetrap.bind("p p", () => onQueuePrevious());
|
||||
Mousetrap.bind("p r", () => onQueueRandom());
|
||||
Mousetrap.bind(",", () => setCollapsed(!collapsed));
|
||||
Mousetrap.bind(".", () => setShowScrubber(!showScrubber));
|
||||
|
||||
return () => {
|
||||
Mousetrap.unbind("a");
|
||||
Mousetrap.unbind("q");
|
||||
Mousetrap.unbind("e");
|
||||
Mousetrap.unbind("k");
|
||||
Mousetrap.unbind("i");
|
||||
Mousetrap.unbind("o");
|
||||
Mousetrap.unbind("p n");
|
||||
Mousetrap.unbind("p p");
|
||||
Mousetrap.unbind("p r");
|
||||
Mousetrap.unbind(",");
|
||||
Mousetrap.unbind(".");
|
||||
};
|
||||
});
|
||||
|
||||
function getCollapseButtonText() {
|
||||
return collapsed ? ">" : "<";
|
||||
}
|
||||
|
||||
if (streamableLoading) return <LoadingIndicator />;
|
||||
if (streamableError) return <ErrorMessage error={streamableError.message} />;
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{scene.title ?? TextUtils.fileNameFromPath(scene.path)}</title>
|
||||
</Helmet>
|
||||
@@ -626,20 +479,6 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
{getCollapseButtonText()}
|
||||
</Button>
|
||||
</div>
|
||||
<div className={`scene-player-container ${collapsed ? "expanded" : ""}`}>
|
||||
{!rerenderPlayer ? (
|
||||
<ScenePlayer
|
||||
className={`w-100 m-sm-auto no-gutter ${
|
||||
!showScrubber ? "hide-scrubber" : ""
|
||||
}`}
|
||||
scene={scene}
|
||||
timestamp={timestamp}
|
||||
autoplay={autoplay}
|
||||
sceneStreams={sceneStreams?.sceneStreams ?? []}
|
||||
onComplete={onComplete}
|
||||
/>
|
||||
) : undefined}
|
||||
</div>
|
||||
<SubmitStashBoxDraft
|
||||
boxes={boxes}
|
||||
entity={scene}
|
||||
@@ -647,20 +486,233 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||
show={showDraftModal}
|
||||
onHide={() => setShowDraftModal(false)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const SceneLoader: React.FC = () => {
|
||||
const { id } = useParams<{ id?: string }>();
|
||||
const { data, loading, error, refetch } = useFindScene(id ?? "");
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
const { configuration } = useContext(ConfigurationContext);
|
||||
const { data, loading, refetch } = useFindScene(id ?? "");
|
||||
const [timestamp, setTimestamp] = useState<number>(getInitialTimestamp());
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [continuePlaylist, setContinuePlaylist] = useState(false);
|
||||
const [showScrubber, setShowScrubber] = useState(
|
||||
configuration?.interface.showScrubber ?? true
|
||||
);
|
||||
|
||||
if (loading) return <LoadingIndicator />;
|
||||
const sceneQueue = useMemo(
|
||||
() => SceneQueue.fromQueryParameters(location.search),
|
||||
[location.search]
|
||||
);
|
||||
const [queueScenes, setQueueScenes] = useState<GQL.SceneDataFragment[]>([]);
|
||||
|
||||
const [queueTotal, setQueueTotal] = useState(0);
|
||||
const [queueStart, setQueueStart] = useState(1);
|
||||
|
||||
const queryParams = useMemo(() => queryString.parse(location.search), [
|
||||
location.search,
|
||||
]);
|
||||
|
||||
function getInitialTimestamp() {
|
||||
const params = queryString.parse(location.search);
|
||||
const initialTimestamp = params?.t ?? "0";
|
||||
return Number.parseInt(
|
||||
Array.isArray(initialTimestamp) ? initialTimestamp[0] : initialTimestamp,
|
||||
10
|
||||
);
|
||||
}
|
||||
|
||||
const autoplay = queryParams?.autoplay === "true";
|
||||
const currentQueueIndex = queueScenes
|
||||
? queueScenes.findIndex((s) => s.id === id)
|
||||
: -1;
|
||||
|
||||
// set up hotkeys
|
||||
useEffect(() => {
|
||||
Mousetrap.bind(".", () => setShowScrubber(!showScrubber));
|
||||
|
||||
return () => {
|
||||
Mousetrap.unbind(".");
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// reset timestamp after notifying player
|
||||
if (timestamp !== -1) setTimestamp(-1);
|
||||
}, [timestamp]);
|
||||
|
||||
async function getQueueFilterScenes(filter: ListFilterModel) {
|
||||
const query = await queryFindScenes(filter);
|
||||
const { scenes, count } = query.data.findScenes;
|
||||
setQueueScenes(scenes);
|
||||
setQueueTotal(count);
|
||||
setQueueStart((filter.currentPage - 1) * filter.itemsPerPage + 1);
|
||||
}
|
||||
|
||||
async function getQueueScenes(sceneIDs: number[]) {
|
||||
const query = await queryFindScenesByID(sceneIDs);
|
||||
const { scenes, count } = query.data.findScenes;
|
||||
setQueueScenes(scenes);
|
||||
setQueueTotal(count);
|
||||
setQueueStart(1);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (sceneQueue.query) {
|
||||
getQueueFilterScenes(sceneQueue.query);
|
||||
} else if (sceneQueue.sceneIDs) {
|
||||
getQueueScenes(sceneQueue.sceneIDs);
|
||||
}
|
||||
}, [sceneQueue]);
|
||||
|
||||
async function onQueueLessScenes() {
|
||||
if (!sceneQueue.query || queueStart <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterCopy = sceneQueue.query.clone();
|
||||
const newStart = queueStart - filterCopy.itemsPerPage;
|
||||
filterCopy.currentPage = Math.ceil(newStart / filterCopy.itemsPerPage);
|
||||
const query = await queryFindScenes(filterCopy);
|
||||
const { scenes } = query.data.findScenes;
|
||||
|
||||
// prepend scenes to scene list
|
||||
const newScenes = scenes.concat(queueScenes);
|
||||
setQueueScenes(newScenes);
|
||||
setQueueStart(newStart);
|
||||
}
|
||||
|
||||
function queueHasMoreScenes() {
|
||||
return queueStart + queueScenes.length - 1 < queueTotal;
|
||||
}
|
||||
|
||||
async function onQueueMoreScenes() {
|
||||
if (!sceneQueue.query || !queueHasMoreScenes()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterCopy = sceneQueue.query.clone();
|
||||
const newStart = queueStart + queueScenes.length;
|
||||
filterCopy.currentPage = Math.ceil(newStart / filterCopy.itemsPerPage);
|
||||
const query = await queryFindScenes(filterCopy);
|
||||
const { scenes } = query.data.findScenes;
|
||||
|
||||
// append scenes to scene list
|
||||
const newScenes = scenes.concat(queueScenes);
|
||||
setQueueScenes(newScenes);
|
||||
// don't change queue start
|
||||
}
|
||||
|
||||
function playScene(sceneID: string, newPage?: number) {
|
||||
sceneQueue.playScene(history, sceneID, {
|
||||
newPage,
|
||||
autoPlay: true,
|
||||
continue: continuePlaylist,
|
||||
});
|
||||
}
|
||||
|
||||
function onQueueNext() {
|
||||
if (!queueScenes) return;
|
||||
if (currentQueueIndex >= 0 && currentQueueIndex < queueScenes.length - 1) {
|
||||
playScene(queueScenes[currentQueueIndex + 1].id);
|
||||
}
|
||||
}
|
||||
|
||||
function onQueuePrevious() {
|
||||
if (!queueScenes) return;
|
||||
if (currentQueueIndex > 0) {
|
||||
playScene(queueScenes[currentQueueIndex - 1].id);
|
||||
}
|
||||
}
|
||||
|
||||
async function onQueueRandom() {
|
||||
if (!queueScenes) return;
|
||||
|
||||
if (sceneQueue.query) {
|
||||
const { query } = sceneQueue;
|
||||
const pages = Math.ceil(queueTotal / query.itemsPerPage);
|
||||
const page = Math.floor(Math.random() * pages) + 1;
|
||||
const index = Math.floor(
|
||||
Math.random() * Math.min(query.itemsPerPage, queueTotal)
|
||||
);
|
||||
const filterCopy = sceneQueue.query.clone();
|
||||
filterCopy.currentPage = page;
|
||||
const queryResults = await queryFindScenes(filterCopy);
|
||||
if (queryResults.data.findScenes.scenes.length > index) {
|
||||
const { id: sceneID } = queryResults!.data!.findScenes!.scenes[index];
|
||||
// navigate to the image player page
|
||||
playScene(sceneID, page);
|
||||
}
|
||||
} else {
|
||||
const index = Math.floor(Math.random() * queueTotal);
|
||||
playScene(queueScenes[index].id);
|
||||
}
|
||||
}
|
||||
|
||||
function onComplete() {
|
||||
// load the next scene if we're autoplaying
|
||||
if (continuePlaylist) {
|
||||
onQueueNext();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (error) return <ErrorMessage error={error.message} />;
|
||||
if (!data?.findScene)
|
||||
if (!loading && !data?.findScene)
|
||||
return <ErrorMessage error={`No scene found with id ${id}.`} />;
|
||||
*/
|
||||
|
||||
return <ScenePage scene={data.findScene} refetch={refetch} />;
|
||||
const scene = data?.findScene;
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
{!loading && scene ? (
|
||||
<ScenePage
|
||||
scene={scene}
|
||||
refetch={refetch}
|
||||
setTimestamp={setTimestamp}
|
||||
queueScenes={queueScenes ?? []}
|
||||
queueStart={queueStart}
|
||||
onQueueNext={onQueueNext}
|
||||
onQueuePrevious={onQueuePrevious}
|
||||
onQueueRandom={onQueueRandom}
|
||||
continuePlaylist={continuePlaylist}
|
||||
playScene={playScene}
|
||||
queueHasMoreScenes={queueHasMoreScenes}
|
||||
onQueueLessScenes={onQueueLessScenes}
|
||||
onQueueMoreScenes={onQueueMoreScenes}
|
||||
collapsed={collapsed}
|
||||
setCollapsed={setCollapsed}
|
||||
setContinuePlaylist={setContinuePlaylist}
|
||||
/>
|
||||
) : (
|
||||
<div className="scene-tabs" />
|
||||
)}
|
||||
<div
|
||||
className={`scene-player-container ${collapsed ? "expanded" : ""} ${
|
||||
!showScrubber ? "hide-scrubber" : ""
|
||||
}`}
|
||||
>
|
||||
<ScenePlayer
|
||||
key="ScenePlayer"
|
||||
className="w-100 m-sm-auto no-gutter"
|
||||
scene={scene}
|
||||
timestamp={timestamp}
|
||||
autoplay={autoplay}
|
||||
onComplete={onComplete}
|
||||
onNext={
|
||||
currentQueueIndex >= 0 && currentQueueIndex < queueScenes.length - 1
|
||||
? onQueueNext
|
||||
: undefined
|
||||
}
|
||||
onPrevious={currentQueueIndex > 0 ? onQueuePrevious : undefined}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SceneLoader;
|
||||
|
||||
Reference in New Issue
Block a user