persist caption across sources

This commit is contained in:
Pas 2026-03-04 21:43:53 -07:00
parent 9009bf814c
commit 314f9574f6
4 changed files with 47 additions and 33 deletions

View file

@ -294,7 +294,7 @@ export function CustomCaptionOption() {
const { t } = useTranslation();
const lang = usePlayerStore((s) => s.caption.selected?.language);
const setCaption = usePlayerStore((s) => s.setCaption);
const setCustomSubs = useSubtitleStore((s) => s.setCustomSubs);
const setSubtitle = useSubtitleStore((s) => s.setSubtitle);
const fileInput = useRef<HTMLInputElement>(null);
const [error, setError] = useState<string | null>(null);
@ -315,7 +315,7 @@ export function CustomCaptionOption() {
srtData: converted,
id: "custom-caption",
});
setCustomSubs();
setSubtitle(true, "custom", "custom-caption");
} catch (err) {
setError(
err instanceof Error
@ -370,7 +370,7 @@ export function CustomCaptionOption() {
export function PasteCaptionOption(props: { selected?: boolean }) {
const { t } = useTranslation();
const setCaption = usePlayerStore((s) => s.setCaption);
const setCustomSubs = useSubtitleStore((s) => s.setCustomSubs);
const setSubtitle = useSubtitleStore((s) => s.setSubtitle);
const setDelay = useSubtitleStore((s) => s.setDelay);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
@ -409,7 +409,7 @@ export function PasteCaptionOption(props: { selected?: boolean }) {
srtData: converted,
id: "pasted-caption",
});
setCustomSubs();
setSubtitle(true, parsedData.language, "pasted-caption");
// Set delay if included in the pasted data, otherwise reset to 0
if (parsedData.delay !== undefined) {
@ -476,7 +476,7 @@ export function CaptionsView({
);
const delay = useSubtitleStore((s) => s.delay);
const appLanguage = useLanguageStore((s) => s.language);
const setCustomSubs = useSubtitleStore((s) => s.setCustomSubs);
const setSubtitle = useSubtitleStore((s) => s.setSubtitle);
const matchScore = useCaptionMatchScore();
// Get combined caption list
@ -580,7 +580,6 @@ export function CaptionsView({
srtData: converted,
id: "custom-caption",
});
setCustomSubs();
} catch (err) {
// Silently fail on drop - user can use the upload button for better error feedback
}

View file

@ -13,7 +13,7 @@ import {
} from "../utils/captions";
export function useCaptions() {
const setLanguage = useSubtitleStore((s) => s.setLanguage);
const setSubtitle = useSubtitleStore((s) => s.setSubtitle);
const enabled = useSubtitleStore((s) => s.enabled);
const resetSubtitleSpecificSettings = useSubtitleStore(
(s) => s.resetSubtitleSpecificSettings,
@ -21,6 +21,9 @@ export function useCaptions() {
const setCaption = usePlayerStore((s) => s.setCaption);
const currentTranslateTask = usePlayerStore((s) => s.caption.translateTask);
const lastSelectedLanguage = useSubtitleStore((s) => s.lastSelectedLanguage);
const lastSelectedSubtitleId = useSubtitleStore(
(s) => s.lastSelectedSubtitleId,
);
const setIsOpenSubtitles = useSubtitleStore((s) => s.setIsOpenSubtitles);
const captionList = usePlayerStore((s) => s.captionList);
@ -53,7 +56,7 @@ export function useCaptions() {
resetSubtitleSpecificSettings();
}
setLanguage(caption.language);
setSubtitle(true, caption.language, caption.id);
// Use native tracks for MP4 streams instead of custom rendering
if (source?.type === "file" && enableNativeSubtitles) {
@ -65,7 +68,7 @@ export function useCaptions() {
},
[
setIsOpenSubtitles,
setLanguage,
setSubtitle,
setCaption,
resetSubtitleSpecificSettings,
source,
@ -135,14 +138,25 @@ export function useCaptions() {
const disable = useCallback(async () => {
setIsOpenSubtitles(false);
setCaption(null);
setLanguage(null);
}, [setCaption, setLanguage, setIsOpenSubtitles]);
setSubtitle(false);
}, [setCaption, setSubtitle, setIsOpenSubtitles]);
const selectLastUsedLanguage = useCallback(async () => {
if (lastSelectedSubtitleId) {
const caption = captions.find((v) => v.id === lastSelectedSubtitleId);
if (caption) return selectCaptionById(caption.id);
}
const language = lastSelectedLanguage ?? "en";
await selectLanguage(language);
return true;
}, [lastSelectedLanguage, selectLanguage]);
}, [
lastSelectedLanguage,
selectLanguage,
lastSelectedSubtitleId,
captions,
selectCaptionById,
]);
const toggleLastUsed = useCallback(async () => {
if (enabled) disable();

View file

@ -26,12 +26,8 @@ export function useInitializeSource() {
);
const { selectLastUsedLanguageIfEnabled } = useCaptions();
// Only select subtitles on initial load, not when source changes
const hasInitializedRef = useRef(false);
useEffect(() => {
if (sourceIdentifier && !hasInitializedRef.current) {
hasInitializedRef.current = true;
if (sourceIdentifier) {
selectLastUsedLanguageIfEnabled();
}
}, [sourceIdentifier, selectLastUsedLanguageIfEnabled]);

View file

@ -59,6 +59,7 @@ export interface SubtitleStore {
};
enabled: boolean;
lastSelectedLanguage: string | null;
lastSelectedSubtitleId: string | null;
isOpenSubtitles: boolean;
styling: SubtitleStyling;
overrideCasing: boolean;
@ -66,9 +67,12 @@ export interface SubtitleStore {
showDelayIndicator: boolean;
updateStyling(newStyling: Partial<SubtitleStyling>): void;
resetStyling(): void;
setLanguage(language: string | null): void;
setSubtitle(
enabled: boolean,
language?: string | null,
subtitleId?: string | null,
): void;
setIsOpenSubtitles(isOpenSubtitles: boolean): void;
setCustomSubs(): void;
setOverrideCasing(enabled: boolean): void;
setDelay(delay: number): void;
importSubtitleLanguage(lang: string | null): void;
@ -84,6 +88,7 @@ export const useSubtitleStore = create(
lastSelectedLanguage: null,
},
lastSelectedLanguage: null,
lastSelectedSubtitleId: null,
isOpenSubtitles: false,
overrideCasing: false,
delay: 0,
@ -105,6 +110,11 @@ export const useSubtitleStore = create(
s.overrideCasing = false;
});
},
setIsOpenSubtitles(isOpenSubtitles) {
set((s) => {
s.isOpenSubtitles = isOpenSubtitles;
});
},
updateStyling(newStyling) {
set((s) => {
if (newStyling.backgroundOpacity !== undefined)
@ -153,21 +163,16 @@ export const useSubtitleStore = create(
};
});
},
setLanguage(lang) {
setSubtitle(enabled, language, subtitleId) {
set((s) => {
s.enabled = !!lang;
if (lang) s.lastSelectedLanguage = lang;
});
},
setIsOpenSubtitles(isOpenSubtitles) {
set((s) => {
s.isOpenSubtitles = isOpenSubtitles;
});
},
setCustomSubs() {
set((s) => {
s.enabled = true;
s.lastSelectedLanguage = null;
s.enabled = enabled;
if (enabled) {
s.lastSelectedLanguage = language ?? null;
s.lastSelectedSubtitleId = subtitleId ?? null;
} else {
s.lastSelectedLanguage = null;
s.lastSelectedSubtitleId = null;
}
});
},
setOverrideCasing(enabled) {