feat: 支持长按右键/D键二倍速播放与视频AB循环

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-11-04 02:00:05 +08:00
co-authored by Cursor
parent bcf1e6e349
commit 11d9d35002
8 changed files with 431 additions and 37 deletions
@@ -14,6 +14,7 @@ interface ImageCarouselProps {
images: ImageData["images"];
currentIndex: number;
isPlaying: boolean;
playbackRate?: number;
segmentProgressRef: RefObject<number>;
mediaSyncToken: number;
loopMode: LoopMode;
@@ -36,6 +37,7 @@ export const ImageCarousel = memo(
images,
currentIndex,
isPlaying,
playbackRate = 1,
segmentProgressRef,
mediaSyncToken,
loopMode,
@@ -58,6 +60,8 @@ export const ImageCarousel = memo(
>(new Map());
const activeVideoIdRef = useRef<string | null>(null);
const lastMediaSyncTokenRef = useRef(mediaSyncToken);
const playbackRateRef = useRef(playbackRate);
playbackRateRef.current = playbackRate;
const pendingSeekRef = useRef<{
imageId: string;
progress: number;
@@ -154,6 +158,7 @@ export const ImageCarousel = memo(
if (!videoEl) return;
videoEl.loop = shouldLoopCurrentVideo;
videoEl.playbackRate = playbackRate;
if (activeVideoIdRef.current !== currentImage.id) {
activeVideoIdRef.current = currentImage.id;
@@ -196,6 +201,7 @@ export const ImageCarousel = memo(
failedAnimatedMap,
images,
isPlaying,
playbackRate,
seekVideoToProgress,
segmentProgressRef,
shouldLoopCurrentVideo,
@@ -293,6 +299,7 @@ export const ImageCarousel = memo(
const callback = (el: HTMLVideoElement | null): void => {
if (el) {
el.playbackRate = playbackRateRef.current;
videoRefs.current.set(imageId, el);
if (Number.isFinite(el.duration) && el.duration > 0) {
onAnimatedDuration(imageId, Math.round(el.duration * 1000));
@@ -377,6 +384,7 @@ export const ImageCarousel = memo(
...mediaStyle,
}}
onLoadedMetadata={(e) => {
e.currentTarget.playbackRate = playbackRateRef.current;
const duration = e.currentTarget.duration;
if (Number.isFinite(duration) && duration > 0) {
onAnimatedDuration(