mirror of https://github.com/stashapp/stash.git
Sub second marker timestamp precision (#5431)
* Allow DurationInput to accept/format timestamps with milliseconds * Get current frame at sub-second precision
This commit is contained in:
parent
0d40056f8c
commit
e8125d08db
|
@ -297,9 +297,13 @@ export const ScenePlayer: React.FC<IScenePlayerProps> = ({
|
|||
sendSetTimestamp((value: number) => {
|
||||
const player = getPlayer();
|
||||
if (player && value >= 0) {
|
||||
player.play()?.then(() => {
|
||||
if (player.hasStarted() && player.paused()) {
|
||||
player.currentTime(value);
|
||||
});
|
||||
} else {
|
||||
player.play()?.then(() => {
|
||||
player.currentTime(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [sendSetTimestamp, getPlayer]);
|
||||
|
|
|
@ -213,7 +213,7 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
|
|||
value={formik.values.seconds}
|
||||
setValue={(v) => formik.setFieldValue("seconds", v)}
|
||||
onReset={() =>
|
||||
formik.setFieldValue("seconds", Math.round(getPlayerPosition() ?? 0))
|
||||
formik.setFieldValue("seconds", getPlayerPosition() ?? 0)
|
||||
}
|
||||
error={error}
|
||||
/>
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
faChevronUp,
|
||||
faClock,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { Button, ButtonGroup, InputGroup, Form } from "react-bootstrap";
|
||||
import { Icon } from "./Icon";
|
||||
import TextUtils from "src/utils/text";
|
||||
|
@ -19,6 +19,8 @@ interface IProps {
|
|||
allowNegative?: boolean;
|
||||
}
|
||||
|
||||
const includeMS = true;
|
||||
|
||||
export const DurationInput: React.FC<IProps> = ({
|
||||
disabled,
|
||||
value,
|
||||
|
@ -96,17 +98,20 @@ export const DurationInput: React.FC<IProps> = ({
|
|||
}
|
||||
}
|
||||
|
||||
let inputValue = "";
|
||||
if (tmpValue !== undefined) {
|
||||
inputValue = tmpValue;
|
||||
} else if (value !== null && value !== undefined) {
|
||||
inputValue = TextUtils.secondsToTimestamp(value);
|
||||
}
|
||||
const inputValue = useMemo(() => {
|
||||
if (tmpValue !== undefined) {
|
||||
return tmpValue;
|
||||
} else if (value !== null && value !== undefined) {
|
||||
return TextUtils.secondsToTimestamp(value, includeMS);
|
||||
}
|
||||
}, [value, tmpValue]);
|
||||
|
||||
const format = "hh:mm:ss.ms";
|
||||
|
||||
if (placeholder) {
|
||||
placeholder = `${placeholder} (hh:mm:ss)`;
|
||||
placeholder = `${placeholder} (${format})`;
|
||||
} else {
|
||||
placeholder = "hh:mm:ss";
|
||||
placeholder = format;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -151,16 +151,20 @@ const fileSizeFractionalDigits = (unit: Unit) => {
|
|||
return 0;
|
||||
};
|
||||
|
||||
// Converts seconds to a hh:mm:ss or mm:ss timestamp.
|
||||
// Converts seconds to a [hh:]mm:ss[.ffff] where hh is only shown if hours is non-zero,
|
||||
// and ffff is shown only if frameRate is set, and the seconds includes a fractional component.
|
||||
// A negative input will result in a -hh:mm:ss or -mm:ss output.
|
||||
// Fractional inputs are truncated.
|
||||
const secondsToTimestamp = (seconds: number) => {
|
||||
const secondsToTimestamp = (secondsInput: number, includeMS?: boolean) => {
|
||||
let neg = false;
|
||||
if (seconds < 0) {
|
||||
if (secondsInput < 0) {
|
||||
neg = true;
|
||||
seconds = -seconds;
|
||||
secondsInput = -secondsInput;
|
||||
}
|
||||
seconds = Math.trunc(seconds);
|
||||
|
||||
const fracSeconds = secondsInput % 1;
|
||||
const ms = Math.round(fracSeconds * 1000);
|
||||
|
||||
let seconds = Math.trunc(secondsInput);
|
||||
|
||||
const s = seconds % 60;
|
||||
seconds = (seconds - s) / 60;
|
||||
|
@ -177,6 +181,11 @@ const secondsToTimestamp = (seconds: number) => {
|
|||
ret = String(m).padStart(2, "0") + ":" + ret;
|
||||
ret = String(h) + ":" + ret;
|
||||
}
|
||||
|
||||
if (includeMS && ms > 0) {
|
||||
ret += "." + ms.toString().padStart(3, "0");
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
return "-" + ret;
|
||||
} else {
|
||||
|
@ -202,6 +211,24 @@ const timestampToSeconds = (v: string | null | undefined) => {
|
|||
return null;
|
||||
}
|
||||
|
||||
let secondsPart = splits[splits.length - 1];
|
||||
let msFrac = 0;
|
||||
if (secondsPart.includes(".")) {
|
||||
const secondsParts = secondsPart.split(".");
|
||||
if (secondsParts.length !== 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
secondsPart = secondsParts[0];
|
||||
|
||||
const msPart = parseInt(secondsParts[1], 10);
|
||||
if (Number.isNaN(msPart)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
msFrac = msPart / 1000;
|
||||
}
|
||||
|
||||
let seconds = 0;
|
||||
let factor = 1;
|
||||
while (splits.length > 0) {
|
||||
|
@ -219,7 +246,7 @@ const timestampToSeconds = (v: string | null | undefined) => {
|
|||
factor *= 60;
|
||||
}
|
||||
|
||||
return seconds;
|
||||
return seconds + msFrac;
|
||||
};
|
||||
|
||||
const fileNameFromPath = (path: string) => {
|
||||
|
|
Loading…
Reference in New Issue