diff --git a/src/components/player/atoms/Settings.tsx b/src/components/player/atoms/Settings.tsx index 63029d1e..cc02ee4e 100644 --- a/src/components/player/atoms/Settings.tsx +++ b/src/components/player/atoms/Settings.tsx @@ -51,7 +51,7 @@ function SettingsOverlay({ id }: { id: string }) { - + diff --git a/src/components/player/atoms/settings/CaptionSettingsView.tsx b/src/components/player/atoms/settings/CaptionSettingsView.tsx index c42abb12..53d67cd5 100644 --- a/src/components/player/atoms/settings/CaptionSettingsView.tsx +++ b/src/components/player/atoms/settings/CaptionSettingsView.tsx @@ -40,6 +40,7 @@ function CaptionSetting(props: { max: number; label: string; min: number; + decimalsAllowed?: number; }) { const inputRef = useRef(null); const ref = useRef(null); @@ -131,7 +132,10 @@ function CaptionSetting(props: { onBlur={(e) => { setIsFocused(false); const num = Number((e.target as HTMLInputElement).value); - if (!Number.isNaN(num)) props.onChange?.(Math.round(num)); + if (!Number.isNaN(num)) + props.onChange?.( + (props.decimalsAllowed ?? 0) === 0 ? Math.round(num) : num + ); }} ref={inputRef} onChange={(e) => @@ -142,13 +146,13 @@ function CaptionSetting(props: { )} @@ -163,7 +167,9 @@ export function CaptionSettingsView({ id }: { id: string }) { const router = useOverlayRouter(id); const styling = useSubtitleStore((s) => s.styling); const overrideCasing = useSubtitleStore((s) => s.overrideCasing); + const delay = useSubtitleStore((s) => s.delay); const setOverrideCasing = useSubtitleStore((s) => s.setOverrideCasing); + const setDelay = useSubtitleStore((s) => s.setDelay); const updateStyling = useSubtitleStore((s) => s.updateStyling); return ( @@ -172,6 +178,15 @@ export function CaptionSettingsView({ id }: { id: string }) { Custom captions + setDelay(v)} + value={delay} + textTransformer={(s) => `${s}s`} + decimalsAllowed={1} + /> s.caption.selected?.srtData); const styling = useSubtitleStore((s) => s.styling); const overrideCasing = useSubtitleStore((s) => s.overrideCasing); + const delay = useSubtitleStore((s) => s.delay); const parsedCaptions = useMemo( () => (srtData ? parseSubtitles(srtData) : []), @@ -79,9 +80,9 @@ export function SubtitleRenderer() { const visibileCaptions = useMemo( () => parsedCaptions.filter(({ start, end }) => - captionIsVisible(start, end, 0, videoTime) + captionIsVisible(start, end, delay, videoTime) ), - [parsedCaptions, videoTime] + [parsedCaptions, videoTime, delay] ); return ( diff --git a/src/stores/subtitles/index.ts b/src/stores/subtitles/index.ts index bf22b071..45da117a 100644 --- a/src/stores/subtitles/index.ts +++ b/src/stores/subtitles/index.ts @@ -24,9 +24,11 @@ export interface SubtitleStore { lastSelectedLanguage: string | null; styling: SubtitleStyling; overrideCasing: boolean; + delay: number; updateStyling(newStyling: Partial): void; setLanguage(language: string | null): void; setOverrideCasing(enabled: boolean): void; + setDelay(delay: number): void; } // TODO add migration from previous stored settings @@ -36,6 +38,7 @@ export const useSubtitleStore = create( enabled: false, lastSelectedLanguage: null, overrideCasing: false, + delay: 0, styling: { color: "#ffffff", backgroundOpacity: 0.5, @@ -62,6 +65,11 @@ export const useSubtitleStore = create( s.overrideCasing = enabled; }); }, + setDelay(delay) { + set((s) => { + s.delay = delay; + }); + }, })), { name: "__MW::subtitles",