Miscellaneous fixes (#24179)

* rename migration

* use ASC composite index for event camera and start_time

the planner still picks for newest-first single-camera queries but doesn't slow down full per-camera scans on a cold cache

* pause playback while the timeline range handles are up

* reduce multi camera seeded export range to 30m

allows both handlebars to fit within most desktop windows
This commit is contained in:
Josh Hawkins
2026-09-12 07:30:04 -06:00
committed by Nicolas Mowen
parent 11b4d34f93
commit d6b93301e2
3 changed files with 32 additions and 28 deletions
@@ -1,6 +1,6 @@
"""Peewee migrations -- 036_add_perf_indexes.py. """Peewee migrations -- 039_add_perf_indexes.py.
Adds composite/single-column indexes to speed up single-camera queries Adds a composite (camera, start_time) index to speed up single-camera queries
issued by the web UI. issued by the web UI.
""" """
@@ -13,7 +13,7 @@ SQL = pw.SQL
def migrate(migrator, database, fake=False, **kwargs): def migrate(migrator, database, fake=False, **kwargs):
migrator.sql( migrator.sql(
'CREATE INDEX IF NOT EXISTS "event_camera_start_time" ' 'CREATE INDEX IF NOT EXISTS "event_camera_start_time" '
'ON "event" ("camera", "start_time" DESC)' 'ON "event" ("camera", "start_time")'
) )
+1 -1
View File
@@ -80,7 +80,7 @@ type ExportOption = (typeof EXPORT_OPTIONS)[number];
export type ExportTab = "export" | "multi"; export type ExportTab = "export" | "multi";
// length of a range seeded around the current playback time // length of a range seeded around the current playback time
const MULTI_CAMERA_RANGE_SECONDS = 3600; const MULTI_CAMERA_RANGE_SECONDS = 1800;
const TIMELINE_SELECTION_SECONDS = 60; const TIMELINE_SELECTION_SECONDS = 60;
type ExportDialogProps = { type ExportDialogProps = {
+28 -24
View File
@@ -231,6 +231,14 @@ export function RecordingView({
const [debugReplayMode, setDebugReplayMode] = useState<ExportMode>("none"); const [debugReplayMode, setDebugReplayMode] = useState<ExportMode>("none");
const [debugReplayRange, setDebugReplayRange] = useState<TimeRange>(); const [debugReplayRange, setDebugReplayRange] = useState<TimeRange>();
// while the range handles are up the player has to stay put: the
// timeline auto-scrolls to follow the playhead once the interaction
// timeout lapses, yanking the view out from under the drag
const selectingRange =
exportMode == "timeline" ||
exportMode == "timeline_multi" ||
debugReplayMode == "timeline";
const [shareTimestampOpen, setShareTimestampOpen] = useState(false); const [shareTimestampOpen, setShareTimestampOpen] = useState(false);
const [shareTimestampAtOpen, setShareTimestampAtOpen] = useState( const [shareTimestampAtOpen, setShareTimestampAtOpen] = useState(
Math.floor(startTime), Math.floor(startTime),
@@ -338,6 +346,19 @@ export function RecordingView({
updateSelectedSegment, updateSelectedSegment,
]); ]);
const wasPlayingBeforeSelectRef = useRef(false);
useEffect(() => {
if (selectingRange) {
wasPlayingBeforeSelectRef.current =
mainControllerRef.current?.isPlaying() ?? false;
mainControllerRef.current?.pause();
} else if (wasPlayingBeforeSelectRef.current) {
wasPlayingBeforeSelectRef.current = false;
mainControllerRef.current?.play();
}
}, [selectingRange]);
const manuallySetCurrentTime = useCallback( const manuallySetCurrentTime = useCallback(
(time: number, play: boolean = false) => { (time: number, play: boolean = false) => {
if (!currentTimeRange) { if (!currentTimeRange) {
@@ -396,7 +417,7 @@ export function RecordingView({
}, [navigate, recording?.navigationSource]); }, [navigate, recording?.navigationSource]);
useEffect(() => { useEffect(() => {
if (!scrubbing) { if (!scrubbing && !selectingRange) {
if (Math.abs(currentTime - playerTime) > 10) { if (Math.abs(currentTime - playerTime) > 10) {
if ( if (
currentTimeRange.after <= currentTime && currentTimeRange.after <= currentTime &&
@@ -423,9 +444,10 @@ export function RecordingView({
mainControllerRef.current?.play(); mainControllerRef.current?.play();
} }
} }
// we only want to seek when current time doesn't match the player update time // we only want to seek when current time doesn't match the player update
// time, and once more on the way out of a range selection
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentTime, scrubbing]); }, [currentTime, scrubbing, selectingRange]);
const [fullResolution, setFullResolution] = useState<VideoResolutionType>({ const [fullResolution, setFullResolution] = useState<VideoResolutionType>({
width: 0, width: 0,
@@ -737,13 +759,7 @@ export function RecordingView({
latestTime={timeRange.before} latestTime={timeRange.before}
mode={debugReplayMode} mode={debugReplayMode}
range={debugReplayRange} range={debugReplayRange}
setRange={(range: TimeRange | undefined) => { setRange={setDebugReplayRange}
setDebugReplayRange(range);
if (range != undefined) {
mainControllerRef.current?.pause();
}
}}
setMode={setDebugReplayMode} setMode={setDebugReplayMode}
/> />
)} )}
@@ -756,13 +772,7 @@ export function RecordingView({
mode={exportMode} mode={exportMode}
range={exportRange} range={exportRange}
showPreview={showExportPreview} showPreview={showExportPreview}
setRange={(range) => { setRange={setExportRange}
setExportRange(range);
if (range != undefined) {
mainControllerRef.current?.pause();
}
}}
setMode={setExportMode} setMode={setExportMode}
setShowPreview={setShowExportPreview} setShowPreview={setShowExportPreview}
/> />
@@ -925,13 +935,7 @@ export function RecordingView({
debugReplayMode={debugReplayMode} debugReplayMode={debugReplayMode}
debugReplayRange={debugReplayRange} debugReplayRange={debugReplayRange}
setDebugReplayMode={setDebugReplayMode} setDebugReplayMode={setDebugReplayMode}
setDebugReplayRange={(range: TimeRange | undefined) => { setDebugReplayRange={setDebugReplayRange}
setDebugReplayRange(range);
if (range != undefined) {
mainControllerRef.current?.pause();
}
}}
onShareTimestamp={onShareReviewLink} onShareTimestamp={onShareReviewLink}
onMotionSearch={ onMotionSearch={
onMotionSearch ? () => onMotionSearch(mainCamera) : undefined onMotionSearch ? () => onMotionSearch(mainCamera) : undefined