From f2c4ecf6c049f2e42185206a1464c220eed33150 Mon Sep 17 00:00:00 2001 From: dogwithakeyboard Date: Sun, 12 Jan 2025 17:20:05 +0000 Subject: [PATCH 1/5] Extend scene queue to markers --- .../components/ScenePlayer/ScenePlayer.tsx | 17 ++ .../Scenes/SceneDetails/QueueViewer.tsx | 101 ++++++++-- .../components/Scenes/SceneDetails/Scene.tsx | 186 ++++++++++++++---- .../src/components/Scenes/SceneMarkerCard.tsx | 14 +- .../Scenes/SceneMarkerCardsGrid.tsx | 4 + .../src/components/Scenes/SceneMarkerList.tsx | 42 ++-- ui/v2.5/src/components/Scenes/styles.scss | 29 ++- ui/v2.5/src/components/Wall/WallItem.tsx | 9 +- ui/v2.5/src/components/Wall/WallPanel.tsx | 9 +- ui/v2.5/src/models/sceneQueue.ts | 59 +++++- 10 files changed, 392 insertions(+), 78 deletions(-) diff --git a/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx b/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx index 24453043bd8..75f08792492 100644 --- a/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx +++ b/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx @@ -203,6 +203,7 @@ interface IScenePlayerProps { autoplay?: boolean; permitLoop?: boolean; initialTimestamp: number; + initialEndstamp: number; sendSetTimestamp: (setTimestamp: (value: number) => void) => void; onComplete: () => void; onNext: () => void; @@ -215,6 +216,7 @@ export const ScenePlayer: React.FC = ({ autoplay, permitLoop = true, initialTimestamp: _initialTimestamp, + initialEndstamp, sendSetTimestamp, onComplete, onNext, @@ -791,6 +793,21 @@ export const ScenePlayer: React.FC = ({ return () => player.off("ended"); }, [getPlayer, onComplete]); + // Try to detect that the player has passed the end point of a Marker + useEffect(() => { + const player = getPlayer(); + if (!player || !initialEndstamp) return; + player.on("timeupdate", function () { + if ( + player.currentTime() >= initialEndstamp && + player.currentTime() <= initialEndstamp + 0.5 + ) { + player.pause(); + onComplete(); + } + }); + }, [getPlayer, initialEndstamp, onComplete]); + function onScrubberScroll() { if (started.current) { getPlayer()?.pause(); diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/QueueViewer.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/QueueViewer.tsx index 6aba56a3772..aafbb907b5e 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/QueueViewer.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/QueueViewer.tsx @@ -12,16 +12,23 @@ import { faStepForward, } from "@fortawesome/free-solid-svg-icons"; import { objectTitle } from "src/core/files"; -import { QueuedScene } from "src/models/sceneQueue"; +import { + QueuedScene, + QueuedSceneMarker, + QueuedItem, +} from "src/models/sceneQueue"; +import { markerTitle } from "src/core/markers"; +import TextUtils from "src/utils/text"; export interface IPlaylistViewer { - scenes: QueuedScene[]; + scenes: QueuedItem[]; currentID?: string; + currentMarkerSeconds?: number; start?: number; continue?: boolean; hasMoreScenes: boolean; setContinue: (v: boolean) => void; - onSceneClicked: (id: string) => void; + onSceneClicked: (scene: QueuedItem) => void; onNext: () => void; onPrevious: () => void; onRandom: () => void; @@ -32,6 +39,7 @@ export interface IPlaylistViewer { export const QueueViewer: React.FC = ({ scenes, currentID, + currentMarkerSeconds, start = 0, continue: continuePlaylist = false, hasMoreScenes, @@ -47,7 +55,16 @@ export const QueueViewer: React.FC = ({ const [lessLoading, setLessLoading] = useState(false); const [moreLoading, setMoreLoading] = useState(false); - const currentIndex = scenes.findIndex((s) => s.id === currentID); + const currentIndex = scenes.findIndex((s) => { + if (s.__typename === "SceneMarker") { + return ( + s.scene.id === currentID && + Math.trunc(s.seconds) === currentMarkerSeconds + ); + } else { + return s.id === currentID; + } + }); useEffect(() => { setLessLoading(false); @@ -58,11 +75,18 @@ export const QueueViewer: React.FC = ({ return scene.id === currentID; } + function isCurrentMarker(marker: QueuedSceneMarker) { + return ( + marker.scene.id === currentID && + Math.trunc(marker.seconds) === currentMarkerSeconds + ); + } + function handleSceneClick( event: React.MouseEvent, - id: string + scene: QueuedItem ) { - onSceneClicked(id); + onSceneClicked(scene); event.preventDefault(); } @@ -76,7 +100,7 @@ export const QueueViewer: React.FC = ({ onMoreScenes(); } - function renderPlaylistEntry(scene: QueuedScene) { + function renderPlaylistEntryScene(scene: QueuedScene) { return (
  • = ({ > handleSceneClick(e, scene.id)} + onClick={(e) => handleSceneClick(e, scene)} >
    @@ -95,9 +119,9 @@ export const QueueViewer: React.FC = ({ />
    - {objectTitle(scene)} - {scene?.studio?.name} - + {objectTitle(scene)} + {scene?.studio?.name} + {scene?.performers ?.map(function (performer) { return performer.name; @@ -112,6 +136,51 @@ export const QueueViewer: React.FC = ({ ); } + function renderPlaylistEntryMarker(marker: QueuedSceneMarker) { + const tags = [marker.primary_tag, ...(marker.tags || [])]; + + return ( +
  • + handleSceneClick(e, marker)} + > +
    +
    + +
    +
    + + {markerTitle(marker)} + {" - "} + {TextUtils.formatTimestampRange( + marker.seconds, + marker.end_seconds ?? undefined + )} + + + {objectTitle(marker.scene)} + + + {marker.scene.performers + ?.map(function (performer) { + return performer.name; + }) + .join(", ")} + + + {tags.map((tag) => tag.name).join(", ")} + +
    +
    + +
  • + ); + } + return (
    @@ -169,7 +238,15 @@ export const QueueViewer: React.FC = ({
    ) : undefined} -
      {scenes.map(renderPlaylistEntry)}
    +
      + {scenes.map((item) => + item.__typename == "Scene" + ? renderPlaylistEntryScene(item) + : item.__typename == "SceneMarker" + ? renderPlaylistEntryMarker(item) + : "" + )} +
    {hasMoreScenes ? (