diff --git a/components/video-page-content.tsx b/components/video-page-content.tsx index bfa52e6..a91429d 100644 --- a/components/video-page-content.tsx +++ b/components/video-page-content.tsx @@ -39,6 +39,7 @@ import type { import { useApprovals } from '@/components/video-page/hooks/use-approvals'; import { useVideoAssets } from '@/components/video-page/hooks/use-video-assets'; import { resolvePublicBunnyCdnHostname } from '@/lib/bunny-cdn'; +import { getSpeedOptionsForProvider } from '@/components/video-page/hooks/video-player-utils'; function formatTime(seconds: number): string { const totalSeconds = Math.floor(seconds); @@ -64,8 +65,6 @@ function formatBunnyQualityLabel( return `Level ${index + 1}`; } -const SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]; - export type VideoPageMode = 'dashboard' | 'watch'; interface VideoPageContentProps { @@ -275,6 +274,7 @@ export function VideoPageContent({ ); }, [video?.versions, activeVersionId]); const activeProviderId = activeVersion?.providerId; + const speedOptions = getSpeedOptionsForProvider(activeProviderId); const activeVersionDuration = activeVersion?.duration; const bunnyCdnHostname = useMemo(() => resolvePublicBunnyCdnHostname(), []); const embedUrl = useMemo(() => { @@ -354,7 +354,7 @@ export function VideoPageContent({ playerRef, formatTime, formatBunnyQualityLabel, - speedOptions: SPEED_OPTIONS, + speedOptions, scheduleWatchProgressSaveRef, setViewingAnnotation, }); @@ -819,7 +819,7 @@ export function VideoPageContent({ qualityOptions={qualityOptions} handleQualityChange={handleQualityChange} playbackSpeed={playbackSpeed} - speedOptions={SPEED_OPTIONS} + speedOptions={speedOptions} handleSpeedChange={handleSpeedChange} toggleFullscreen={toggleFullscreen} showComments={showComments} diff --git a/components/video-page/bunny-preview-player.tsx b/components/video-page/bunny-preview-player.tsx index 1ce1c02..6c0804b 100644 --- a/components/video-page/bunny-preview-player.tsx +++ b/components/video-page/bunny-preview-player.tsx @@ -21,6 +21,10 @@ import { } from '@/components/ui/dropdown-menu'; import { resolvePublicBunnyCdnHostname } from '@/lib/bunny-cdn'; import { cn } from '@/lib/utils'; +import { + NATIVE_SPEED_OPTIONS, + SILENT_ABOVE_SPEED, +} from '@/components/video-page/hooks/video-player-utils'; import type { BunnyPlaybackState, BunnyQualityOption } from '@/components/video-page/types'; interface BunnyPreviewPlayerProps { @@ -35,8 +39,6 @@ export interface BunnyPreviewPlayerHandle { toggleMute: () => void; } -const SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]; - function formatTime(value: number): string { if (!Number.isFinite(value) || value < 0) return '0:00'; const total = Math.floor(value); @@ -635,9 +637,14 @@ export const BunnyPreviewPlayer = forwardRef - {SPEED_OPTIONS.map((speed) => ( + {NATIVE_SPEED_OPTIONS.map((speed) => ( handleSpeedChange(speed)}> {speed}x {speed === playbackSpeed ? '(Current)' : ''} + {speed > SILENT_ABOVE_SPEED && ( + + no audio + + )} ))} diff --git a/components/video-page/hooks/video-player-utils.ts b/components/video-page/hooks/video-player-utils.ts index 1f3529f..b570ecf 100644 --- a/components/video-page/hooks/video-player-utils.ts +++ b/components/video-page/hooks/video-player-utils.ts @@ -95,6 +95,23 @@ export function timeFromClientX( return percentage * duration; } +// Speed ladders. YouTube is played through its iframe API, which silently +// ignores any rate outside the list `getAvailablePlaybackRates()` returns, so +// 2x is the ceiling there. Bunny and R2 are plain