-
-
Notifications
You must be signed in to change notification settings - Fork 2k
fix: ripple timeline to drop removed ranges instead of leaving dead zones #909
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,13 +2,14 @@ import type { Span } from "dnd-timeline"; | |
| import { type Dispatch, type MutableRefObject, type SetStateAction, useCallback } from "react"; | ||
| import { toast } from "sonner"; | ||
| import { planClipSpeedChange } from "../clipSpeedChange"; | ||
| import type { | ||
| AnnotationRegion, | ||
| AudioRegion, | ||
| ClipRegion, | ||
| EditorEffectSection, | ||
| SpeedRegion, | ||
| ZoomRegion, | ||
| import { | ||
| getClipTimelineStartMs, | ||
| type AnnotationRegion, | ||
| type AudioRegion, | ||
| type ClipRegion, | ||
| type EditorEffectSection, | ||
| type SpeedRegion, | ||
| type ZoomRegion, | ||
| } from "../types"; | ||
|
|
||
| type Translator = ( | ||
|
|
@@ -79,15 +80,25 @@ export function useClipRegionCommands({ | |
|
|
||
| const handleClipSplit = useCallback( | ||
| (splitMs: number) => { | ||
| const target = clipRegions.find( | ||
| (clip) => splitMs > clip.startMs && splitMs < clip.endMs, | ||
| ); | ||
| const target = clipRegions.find((clip) => { | ||
| const timelineStart = getClipTimelineStartMs(clip, clipRegions); | ||
| const timelineEnd = timelineStart + Math.max(0, clip.endMs - clip.startMs); | ||
| return splitMs > timelineStart && splitMs < timelineEnd; | ||
| }); | ||
| if (!target) return; | ||
| const leftId = `clip-${nextClipIdRef.current++}`; | ||
| const rightId = `clip-${nextClipIdRef.current++}`; | ||
| const timelineStart = getClipTimelineStartMs(target, clipRegions); | ||
| const splitAt = Math.round(splitMs); | ||
| const left: ClipRegion = { ...target, id: leftId, endMs: splitAt }; | ||
| const right: ClipRegion = { ...target, id: rightId, startMs: splitAt }; | ||
| const splitOffset = splitAt - timelineStart; | ||
| const newSourceStart = Math.round(target.startMs + splitOffset * target.speed); | ||
| const left: ClipRegion = { ...target, id: leftId, endMs: newSourceStart }; | ||
| const right: ClipRegion = { | ||
| ...target, | ||
| id: rightId, | ||
| startMs: newSourceStart, | ||
| endMs: newSourceStart + Math.max(0, target.endMs - target.startMs - splitOffset), | ||
| }; | ||
| setClipRegions((current) => | ||
| current.flatMap((clip) => (clip.id === target.id ? [left, right] : [clip])), | ||
| ); | ||
|
|
@@ -99,30 +110,41 @@ export function useClipRegionCommands({ | |
| const handleClipSpanChange = useCallback( | ||
| (id: string, span: Span) => { | ||
| const oldClip = clipRegions.find((clip) => clip.id === id); | ||
| const newStart = Math.round(span.start); | ||
| const newEnd = Math.round(span.end); | ||
| const newTimelineStart = Math.round(span.start); | ||
| const newTimelineEnd = Math.round(span.end); | ||
| const oldTimelineStart = oldClip | ||
| ? getClipTimelineStartMs(oldClip, clipRegions) | ||
| : 0; | ||
| const oldTimelineEnd = | ||
| oldTimelineStart + Math.max(0, (oldClip?.endMs ?? 0) - (oldClip?.startMs ?? 0)); | ||
| const newTimelineDuration = Math.max(0, newTimelineEnd - newTimelineStart); | ||
| const speed = oldClip && oldClip.speed > 0 ? oldClip.speed : 1; | ||
| const newSourceStart = oldClip | ||
| ? Math.round(oldClip.startMs + (newTimelineStart - oldTimelineStart) * speed) | ||
| : 0; | ||
| const newEndMs = newSourceStart + newTimelineDuration; | ||
| const removedSegments = oldClip | ||
| ? [ | ||
| ...(newStart > oldClip.startMs | ||
| ? [{ startMs: oldClip.startMs, endMs: newStart }] | ||
| ...(newTimelineStart > oldTimelineStart | ||
| ? [{ startMs: oldTimelineStart, endMs: newTimelineStart }] | ||
| : []), | ||
| ...(newEnd < oldClip.endMs | ||
| ? [{ startMs: newEnd, endMs: oldClip.endMs }] | ||
| ...(newTimelineEnd < oldTimelineEnd | ||
| ? [{ startMs: newTimelineEnd, endMs: oldTimelineEnd }] | ||
| : []), | ||
|
Comment on lines
+132
to
137
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
# Description: Determine whether zoom, annotation, speed, and audio regions are stored in source or timeline coordinates.
set -euo pipefail
rg -n -C 4 --type=ts 'mapTimelineTimeToSourceTime|mapSourceTimeToTimelineTime' src/components/video-editor
fd -t f -e ts -e tsx . src/components/video-editor --exec rg -n -C 3 'zoomRegions|speedRegions' {} \
| rg -n -C 3 'source|timeline' || trueRepository: webadderallorg/Recordly Length of output: 27541 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- useClipRegionCommands.ts ---'
sed -n '1,285p' src/components/video-editor/hooks/useClipRegionCommands.ts
printf '%s\n' '--- types.ts region definitions and timeline mapping ---'
sed -n '1,210p' src/components/video-editor/types.ts
sed -n '285,410p' src/components/video-editor/types.ts
printf '%s\n' '--- projection and region command consumers ---'
sed -n '75,145p' src/components/video-editor/hooks/useTimelineProjection.ts
rg -n -C 6 --glob '*.ts' --glob '*.tsx' \
'handleZoom(Add|Suggested|SpanChange)|handleAnnotation|handleSpeed|handleAudio|setZoomRegions|setAnnotationRegions|setSpeedRegions|setAudioRegions|mapTimelineTimeToSourceTime|mapSourceTimeToTimelineTime' \
src/components/video-editor/hooks src/components/video-editor/layout src/components/video-editor/modelRepository: webadderallorg/Recordly Length of output: 50380 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- region interfaces and mapping helpers ---'
rg -n -A18 -B4 \
'interface (AnnotationRegion|SpeedRegion|AudioRegion|ClipRegion)|function getKeptTimelineSpans|effectiveZoomRegions|effectiveCaptionRegions' \
src/components/video-editor/types.ts \
src/components/video-editor/hooks/useTimelineProjection.ts
printf '%s\n' '--- region creation and span-edit handlers ---'
for f in \
src/components/video-editor/hooks/useZoomRegionCommands.ts \
src/components/video-editor/hooks/useAnnotationRegionCommands.ts \
src/components/video-editor/hooks/useSpeedRegionCommands.ts \
src/components/video-editor/hooks/useAudioRegionCommands.ts \
src/components/video-editor/layout/EditorTimelinePanel.tsx
do
if [ -f "$f" ]; then
echo "### $f"
rg -n -C 8 \
'handle(Zoom|Annotation|Speed|Audio)(Added|Suggested|SpanChange)|on(Zoom|Annotation|Speed|Audio)SpanChange|zoomRegions=|annotationRegions=|speedRegions=|audioRegions=' \
"$f" || true
fi
doneRepository: webadderallorg/Recordly Length of output: 19923 🏁 Script executed: #!/bin/bash
set -euo pipefail
for f in \
src/components/video-editor/hooks/useZoomRegionCommands.ts \
src/components/video-editor/hooks/useAnnotationRegionCommands.ts \
src/components/video-editor/hooks/useSpeedRegionCommands.ts \
src/components/video-editor/hooks/useAudioRegionCommands.ts \
src/components/video-editor/layout/EditorTimelinePanel.tsx
do
[ -f "$f" ] || continue
echo "### $f"
rg -n -C 5 \
'handle(Zoom|Annotation|Speed|Audio)(Added|Suggested|SpanChange)|on(Zoom|Annotation|Speed|Audio)SpanChange|zoomRegions=|annotationRegions=|speedRegions=|audioRegions=' \
"$f" || true
doneRepository: webadderallorg/Recordly Length of output: 6104 Use timeline bounds when deleting a clip.
🤖 Prompt for AI Agents |
||
| ] | ||
| : []; | ||
|
|
||
| if (oldClip) { | ||
| const startDelta = newStart - oldClip.startMs; | ||
| const endDelta = newEnd - oldClip.endMs; | ||
| if (Math.abs(startDelta - endDelta) < 1 && Math.abs(startDelta) > 0) { | ||
| const timelineStartDelta = newTimelineStart - oldTimelineStart; | ||
| const timelineEndDelta = newTimelineEnd - oldTimelineEnd; | ||
| if (Math.abs(timelineStartDelta - timelineEndDelta) < 1 && Math.abs(timelineStartDelta) > 0) { | ||
| setZoomRegions((current) => | ||
| current.map((zoom) => | ||
| zoom.startMs < oldClip.endMs && zoom.endMs > oldClip.startMs | ||
| zoom.startMs < oldTimelineEnd && zoom.endMs > oldTimelineStart | ||
| ? { | ||
| ...zoom, | ||
| startMs: zoom.startMs + startDelta, | ||
| endMs: zoom.endMs + startDelta, | ||
| startMs: zoom.startMs + timelineStartDelta, | ||
| endMs: zoom.endMs + timelineStartDelta, | ||
| } | ||
| : zoom, | ||
| ), | ||
|
|
@@ -150,7 +172,9 @@ export function useClipRegionCommands({ | |
|
|
||
| setClipRegions((current) => | ||
| current.map((clip) => | ||
| clip.id === id ? { ...clip, startMs: newStart, endMs: newEnd } : clip, | ||
| clip.id === id | ||
| ? { ...clip, startMs: newSourceStart, endMs: newEndMs } | ||
| : clip, | ||
| ), | ||
| ); | ||
| }, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.