import { Tab, Nav, Dropdown, Button, ButtonGroup } from "react-bootstrap"; import queryString from "query-string"; import React, { useEffect, useState } from "react"; import { useParams, useLocation, useHistory, Link } from "react-router-dom"; import * as GQL from "src/core/generated-graphql"; import { useFindScene, useSceneIncrementO, useSceneDecrementO, useSceneResetO, useSceneStreams, useSceneGenerateScreenshot, useSceneUpdate, } from "src/core/StashService"; import { GalleryViewer } from "src/components/Galleries/GalleryViewer"; import { ErrorMessage, LoadingIndicator, Icon } from "src/components/Shared"; import { useToast } from "src/hooks"; import { ScenePlayer } from "src/components/ScenePlayer"; import { TextUtils, JWUtils } from "src/utils"; import Mousetrap from "mousetrap"; import { SceneMarkersPanel } from "./SceneMarkersPanel"; import { SceneFileInfoPanel } from "./SceneFileInfoPanel"; import { SceneEditPanel } from "./SceneEditPanel"; import { SceneDetailPanel } from "./SceneDetailPanel"; import { OCounterButton } from "./OCounterButton"; import { SceneMoviePanel } from "./SceneMoviePanel"; import { DeleteScenesDialog } from "../DeleteScenesDialog"; import { SceneGenerateDialog } from "../SceneGenerateDialog"; import { SceneVideoFilterPanel } from "./SceneVideoFilterPanel"; import { OrganizedButton } from "./OrganizedButton"; interface ISceneParams { id?: string; } export const Scene: React.FC = () => { const { id = "new" } = useParams(); const location = useLocation(); const history = useHistory(); const Toast = useToast(); const [updateScene] = useSceneUpdate(); const [generateScreenshot] = useSceneGenerateScreenshot(); const [timestamp, setTimestamp] = useState(getInitialTimestamp()); const [collapsed, setCollapsed] = useState(false); const { data, error, loading } = useFindScene(id); const scene = data?.findScene; const { data: sceneStreams, error: streamableError, loading: streamableLoading, } = useSceneStreams(id); const [oLoading, setOLoading] = useState(false); const [incrementO] = useSceneIncrementO(scene?.id ?? "0"); const [decrementO] = useSceneDecrementO(scene?.id ?? "0"); const [resetO] = useSceneResetO(scene?.id ?? "0"); const [organizedLoading, setOrganizedLoading] = useState(false); const [activeTabKey, setActiveTabKey] = useState("scene-details-panel"); const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); const [isGenerateDialogOpen, setIsGenerateDialogOpen] = useState(false); const queryParams = queryString.parse(location.search); const autoplay = queryParams?.autoplay === "true"; function getInitialTimestamp() { const params = queryString.parse(location.search); const initialTimestamp = params?.t ?? "0"; return Number.parseInt( Array.isArray(initialTimestamp) ? initialTimestamp[0] : initialTimestamp, 10 ); } const onOrganizedClick = async () => { try { setOrganizedLoading(true); await updateScene({ variables: { input: { id: scene?.id ?? "", organized: !scene?.organized, }, }, }); } catch (e) { Toast.error(e); } finally { setOrganizedLoading(false); } }; const onIncrementClick = async () => { try { setOLoading(true); await incrementO(); } catch (e) { Toast.error(e); } finally { setOLoading(false); } }; const onDecrementClick = async () => { try { setOLoading(true); await decrementO(); } catch (e) { Toast.error(e); } finally { setOLoading(false); } }; const onResetClick = async () => { try { setOLoading(true); await resetO(); } catch (e) { Toast.error(e); } finally { setOLoading(false); } }; function onClickMarker(marker: GQL.SceneMarkerDataFragment) { setTimestamp(marker.seconds); } async function onGenerateScreenshot(at?: number) { if (!scene) { return; } await generateScreenshot({ variables: { id: scene.id, at, }, }); Toast.success({ content: "Generating screenshot" }); } function onDeleteDialogClosed(deleted: boolean) { setIsDeleteAlertOpen(false); if (deleted) { history.push("/scenes"); } } function maybeRenderDeleteDialog() { if (isDeleteAlertOpen && scene) { return ( ); } } function maybeRenderSceneGenerateDialog() { if (isGenerateDialogOpen && scene) { return ( { setIsGenerateDialogOpen(false); }} /> ); } } function renderOperations() { return ( setIsGenerateDialogOpen(true)} > Generate... onGenerateScreenshot(JWUtils.getPlayer().getPosition()) } > Generate thumbnail from current onGenerateScreenshot()} > Generate default thumbnail setIsDeleteAlertOpen(true)} > Delete Scene ); } function renderTabs() { if (!scene) { return; } return ( k && setActiveTabKey(k)} >
{scene.gallery ? ( ) : ( "" )} setIsDeleteAlertOpen(true)} />
); } // set up hotkeys useEffect(() => { Mousetrap.bind("a", () => setActiveTabKey("scene-details-panel")); Mousetrap.bind("e", () => setActiveTabKey("scene-edit-panel")); Mousetrap.bind("k", () => setActiveTabKey("scene-markers-panel")); Mousetrap.bind("f", () => setActiveTabKey("scene-file-info-panel")); Mousetrap.bind("o", () => onIncrementClick()); return () => { Mousetrap.unbind("a"); Mousetrap.unbind("e"); Mousetrap.unbind("k"); Mousetrap.unbind("f"); Mousetrap.unbind("o"); }; }); function getCollapseButtonText() { return collapsed ? ">" : "<"; } if (loading || streamableLoading) return ; if (error) return ; if (streamableError) return ; if (!scene) return ; return (
{maybeRenderSceneGenerateDialog()} {maybeRenderDeleteDialog()}
{scene.studio && (

{`${scene.studio.name}

)}

{scene.title ?? TextUtils.fileNameFromPath(scene.path)}

{renderTabs()}
); };