mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-07 03:35:26 +03:00
Optimizations and improvements
This commit is contained in:
parent
d1b1c67062
commit
88820613ce
@ -76,7 +76,7 @@ const domEvents: TimelineEventsWithMissing[] = [
|
||||
type ActivityScrubberProps = {
|
||||
className?: string;
|
||||
items?: TimelineItem[];
|
||||
timeBars?: { time: DateType; id?: IdType | undefined }[];
|
||||
timeBars?: { time: DateType; id: IdType }[];
|
||||
groups?: TimelineGroup[];
|
||||
options?: TimelineOptions;
|
||||
} & TimelineEventsHandlers;
|
||||
@ -94,6 +94,9 @@ function ActivityScrubber({
|
||||
timeline: null,
|
||||
});
|
||||
const [currentTime, setCurrentTime] = useState(Date.now());
|
||||
const [customTimes, setCustomTimes] = useState<
|
||||
{ id: IdType; time: DateType }[]
|
||||
>([]);
|
||||
|
||||
const defaultOptions: TimelineOptions = {
|
||||
width: "100%",
|
||||
@ -161,6 +164,41 @@ function ActivityScrubber({
|
||||
};
|
||||
}, [containerRef]);
|
||||
|
||||
// need to keep custom times in sync
|
||||
useEffect(() => {
|
||||
if (!timelineRef.current.timeline || timeBars == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
setCustomTimes((prevTimes) => {
|
||||
if (prevTimes.length == 0 && timeBars.length == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
prevTimes
|
||||
.filter((x) => timeBars.find((y) => x.id == y.id) == undefined)
|
||||
.forEach((time) => {
|
||||
try {
|
||||
timelineRef.current.timeline?.removeCustomTime(time.id);
|
||||
} catch {}
|
||||
});
|
||||
|
||||
timeBars.forEach((time) => {
|
||||
try {
|
||||
const existing = timelineRef.current.timeline?.getCustomTime(time.id);
|
||||
|
||||
if (existing != time.time) {
|
||||
timelineRef.current.timeline?.setCustomTime(time.time, time.id);
|
||||
}
|
||||
} catch {
|
||||
timelineRef.current.timeline?.addCustomTime(time.time, time.id);
|
||||
}
|
||||
});
|
||||
|
||||
return timeBars;
|
||||
});
|
||||
}, [timeBars, timelineRef]);
|
||||
|
||||
return (
|
||||
<div className={className || ""}>
|
||||
<div ref={containerRef} />
|
||||
|
||||
@ -111,10 +111,20 @@ export function getTimelineHoursForDay(
|
||||
const now = new Date();
|
||||
const data: TimelinePlayback[] = [];
|
||||
const startDay = new Date(timestamp * 1000);
|
||||
startDay.setHours(23, 59, 59, 999);
|
||||
const dayEnd = startDay.getTime() / 1000;
|
||||
startDay.setHours(0, 0, 0, 0);
|
||||
let start = startDay.getTime() / 1000;
|
||||
let end = 0;
|
||||
|
||||
const relevantPreviews = allPreviews.filter((preview) => {
|
||||
return (
|
||||
preview.camera == camera &&
|
||||
preview.start >= start &&
|
||||
Math.floor(preview.end - 1) <= dayEnd
|
||||
);
|
||||
});
|
||||
|
||||
const dayIdx = Object.keys(cards).find((day) => {
|
||||
if (parseInt(day) > start) {
|
||||
return false;
|
||||
@ -156,12 +166,9 @@ export function getTimelineHoursForDay(
|
||||
return [];
|
||||
})
|
||||
: [];
|
||||
const previewCheck = start + 30; // preview can start after the hour
|
||||
const relevantPreview = Object.values(allPreviews || []).find(
|
||||
const relevantPreview = relevantPreviews.find(
|
||||
(preview) =>
|
||||
preview.camera == camera &&
|
||||
preview.start < previewCheck &&
|
||||
preview.end > previewCheck
|
||||
Math.round(preview.start) >= start && Math.floor(preview.end) <= end
|
||||
);
|
||||
data.push({
|
||||
camera,
|
||||
|
||||
@ -42,6 +42,11 @@ export default function DesktopTimelineView({
|
||||
|
||||
const [seeking, setSeeking] = useState(false);
|
||||
const [timeToSeek, setTimeToSeek] = useState<number | undefined>(undefined);
|
||||
const [timelineTime, setTimelineTime] = useState(
|
||||
initialPlayback.timelineItems.length > 0
|
||||
? initialPlayback.timelineItems[0].timestamp
|
||||
: initialPlayback.range.start
|
||||
);
|
||||
|
||||
const annotationOffset = useMemo(() => {
|
||||
if (!config) {
|
||||
@ -54,14 +59,6 @@ export default function DesktopTimelineView({
|
||||
);
|
||||
}, [config]);
|
||||
|
||||
const timelineTime = useMemo(() => {
|
||||
if (!selectedPlayback || selectedPlayback.timelineItems.length == 0) {
|
||||
return selectedPlayback.range.start;
|
||||
}
|
||||
|
||||
return selectedPlayback.timelineItems.at(0)!!.timestamp;
|
||||
}, [selectedPlayback]);
|
||||
|
||||
const recordingParams = useMemo(() => {
|
||||
return {
|
||||
before: selectedPlayback.range.end,
|
||||
@ -121,36 +118,6 @@ export default function DesktopTimelineView({
|
||||
[annotationOffset, recordings, playerRef]
|
||||
);
|
||||
|
||||
const onScrubTime = useCallback(
|
||||
(data: { time: Date }) => {
|
||||
if (!selectedPlayback.relevantPreview) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerRef.current?.paused() == false) {
|
||||
setScrubbing(true);
|
||||
playerRef.current?.pause();
|
||||
}
|
||||
|
||||
const seekTimestamp = data.time.getTime() / 1000;
|
||||
const seekTime = seekTimestamp - selectedPlayback.relevantPreview.start;
|
||||
setTimeToSeek(Math.round(seekTime));
|
||||
},
|
||||
[scrubbing, playerRef, selectedPlayback]
|
||||
);
|
||||
|
||||
const onStopScrubbing = useCallback(
|
||||
(data: { time: Date }) => {
|
||||
const playbackTime = data.time.getTime() / 1000;
|
||||
playerRef.current?.currentTime(
|
||||
playbackTime - selectedPlayback.range.start
|
||||
);
|
||||
setScrubbing(false);
|
||||
playerRef.current?.play();
|
||||
},
|
||||
[selectedPlayback, playerRef]
|
||||
);
|
||||
|
||||
// handle seeking to next frame when seek is finished
|
||||
useEffect(() => {
|
||||
if (seeking) {
|
||||
@ -165,15 +132,33 @@ export default function DesktopTimelineView({
|
||||
|
||||
// handle loading main playback when selected hour changes
|
||||
useEffect(() => {
|
||||
if (!playerRef.current) {
|
||||
if (!playerRef.current || !previewRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimelineTime(
|
||||
selectedPlayback.timelineItems.length > 0
|
||||
? selectedPlayback.timelineItems[0].timestamp
|
||||
: selectedPlayback.range.start
|
||||
);
|
||||
|
||||
playerRef.current.src({
|
||||
src: playbackUri,
|
||||
type: "application/vnd.apple.mpegurl",
|
||||
});
|
||||
}, [playerRef, selectedPlayback]);
|
||||
|
||||
if (selectedPlayback.relevantPreview) {
|
||||
console.log(
|
||||
`found relevant preview with start ${new Date(
|
||||
selectedPlayback.relevantPreview.start * 1000
|
||||
)} for ${new Date(selectedPlayback.range.start * 1000)}`
|
||||
);
|
||||
previewRef.current.src({
|
||||
src: selectedPlayback.relevantPreview.src,
|
||||
type: selectedPlayback.relevantPreview.type,
|
||||
});
|
||||
}
|
||||
}, [playerRef, previewRef, selectedPlayback]);
|
||||
|
||||
const timelineStack = useMemo(
|
||||
() =>
|
||||
@ -181,7 +166,7 @@ export default function DesktopTimelineView({
|
||||
selectedPlayback.camera,
|
||||
timelineData,
|
||||
allPreviews,
|
||||
timelineTime
|
||||
selectedPlayback.range.start + 60
|
||||
),
|
||||
[]
|
||||
);
|
||||
@ -216,9 +201,15 @@ export default function DesktopTimelineView({
|
||||
seekOptions={{ forward: 10, backward: 5 }}
|
||||
onReady={(player) => {
|
||||
playerRef.current = player;
|
||||
player.currentTime(
|
||||
timelineTime - selectedPlayback.range.start
|
||||
);
|
||||
|
||||
if (selectedPlayback.timelineItems.length > 0) {
|
||||
player.currentTime(
|
||||
selectedPlayback.timelineItems[0].timestamp -
|
||||
selectedPlayback.range.start
|
||||
);
|
||||
} else {
|
||||
player.currentTime(0);
|
||||
}
|
||||
player.on("playing", () => {
|
||||
onSelectItem(undefined);
|
||||
});
|
||||
@ -285,13 +276,18 @@ export default function DesktopTimelineView({
|
||||
return (
|
||||
<div
|
||||
key={timeline.range.start}
|
||||
className={`${isSelected ? "border border-primary" : ""}`}
|
||||
className={`p-1 ${isSelected ? "border border-primary" : ""}`}
|
||||
>
|
||||
<ActivityScrubber
|
||||
items={[]}
|
||||
timeBars={
|
||||
isSelected && selectedPlayback.relevantPreview
|
||||
? [{ time: new Date(timelineTime * 1000), id: "playback" }]
|
||||
? [
|
||||
{
|
||||
time: new Date(timelineTime * 1000),
|
||||
id: "playback",
|
||||
},
|
||||
]
|
||||
: []
|
||||
}
|
||||
options={{
|
||||
@ -300,8 +296,30 @@ export default function DesktopTimelineView({
|
||||
max: new Date(timeline.range.end * 1000),
|
||||
zoomable: false,
|
||||
}}
|
||||
timechangeHandler={onScrubTime}
|
||||
timechangedHandler={onStopScrubbing}
|
||||
timechangeHandler={(data) => {
|
||||
if (!timeline.relevantPreview) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerRef.current?.paused() == false) {
|
||||
setScrubbing(true);
|
||||
playerRef.current?.pause();
|
||||
}
|
||||
|
||||
const seekTimestamp = data.time.getTime() / 1000;
|
||||
const seekTime =
|
||||
seekTimestamp - timeline.relevantPreview.start;
|
||||
setTimelineTime(seekTimestamp);
|
||||
setTimeToSeek(Math.round(seekTime));
|
||||
}}
|
||||
timechangedHandler={(data) => {
|
||||
const playbackTime = data.time.getTime() / 1000;
|
||||
playerRef.current?.currentTime(
|
||||
playbackTime - timeline.range.start
|
||||
);
|
||||
setScrubbing(false);
|
||||
playerRef.current?.play();
|
||||
}}
|
||||
doubleClickHandler={() => {
|
||||
setSelectedPlayback(timeline);
|
||||
}}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user