mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-11 17:55:33 +00:00
persist caption across sources
This commit is contained in:
parent
9009bf814c
commit
314f9574f6
4 changed files with 47 additions and 33 deletions
|
|
@ -294,7 +294,7 @@ export function CustomCaptionOption() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const lang = usePlayerStore((s) => s.caption.selected?.language);
|
const lang = usePlayerStore((s) => s.caption.selected?.language);
|
||||||
const setCaption = usePlayerStore((s) => s.setCaption);
|
const setCaption = usePlayerStore((s) => s.setCaption);
|
||||||
const setCustomSubs = useSubtitleStore((s) => s.setCustomSubs);
|
const setSubtitle = useSubtitleStore((s) => s.setSubtitle);
|
||||||
const fileInput = useRef<HTMLInputElement>(null);
|
const fileInput = useRef<HTMLInputElement>(null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
|
@ -315,7 +315,7 @@ export function CustomCaptionOption() {
|
||||||
srtData: converted,
|
srtData: converted,
|
||||||
id: "custom-caption",
|
id: "custom-caption",
|
||||||
});
|
});
|
||||||
setCustomSubs();
|
setSubtitle(true, "custom", "custom-caption");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(
|
setError(
|
||||||
err instanceof Error
|
err instanceof Error
|
||||||
|
|
@ -370,7 +370,7 @@ export function CustomCaptionOption() {
|
||||||
export function PasteCaptionOption(props: { selected?: boolean }) {
|
export function PasteCaptionOption(props: { selected?: boolean }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const setCaption = usePlayerStore((s) => s.setCaption);
|
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 setDelay = useSubtitleStore((s) => s.setDelay);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
@ -409,7 +409,7 @@ export function PasteCaptionOption(props: { selected?: boolean }) {
|
||||||
srtData: converted,
|
srtData: converted,
|
||||||
id: "pasted-caption",
|
id: "pasted-caption",
|
||||||
});
|
});
|
||||||
setCustomSubs();
|
setSubtitle(true, parsedData.language, "pasted-caption");
|
||||||
|
|
||||||
// Set delay if included in the pasted data, otherwise reset to 0
|
// Set delay if included in the pasted data, otherwise reset to 0
|
||||||
if (parsedData.delay !== undefined) {
|
if (parsedData.delay !== undefined) {
|
||||||
|
|
@ -476,7 +476,7 @@ export function CaptionsView({
|
||||||
);
|
);
|
||||||
const delay = useSubtitleStore((s) => s.delay);
|
const delay = useSubtitleStore((s) => s.delay);
|
||||||
const appLanguage = useLanguageStore((s) => s.language);
|
const appLanguage = useLanguageStore((s) => s.language);
|
||||||
const setCustomSubs = useSubtitleStore((s) => s.setCustomSubs);
|
const setSubtitle = useSubtitleStore((s) => s.setSubtitle);
|
||||||
const matchScore = useCaptionMatchScore();
|
const matchScore = useCaptionMatchScore();
|
||||||
|
|
||||||
// Get combined caption list
|
// Get combined caption list
|
||||||
|
|
@ -580,7 +580,6 @@ export function CaptionsView({
|
||||||
srtData: converted,
|
srtData: converted,
|
||||||
id: "custom-caption",
|
id: "custom-caption",
|
||||||
});
|
});
|
||||||
setCustomSubs();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Silently fail on drop - user can use the upload button for better error feedback
|
// Silently fail on drop - user can use the upload button for better error feedback
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {
|
||||||
} from "../utils/captions";
|
} from "../utils/captions";
|
||||||
|
|
||||||
export function useCaptions() {
|
export function useCaptions() {
|
||||||
const setLanguage = useSubtitleStore((s) => s.setLanguage);
|
const setSubtitle = useSubtitleStore((s) => s.setSubtitle);
|
||||||
const enabled = useSubtitleStore((s) => s.enabled);
|
const enabled = useSubtitleStore((s) => s.enabled);
|
||||||
const resetSubtitleSpecificSettings = useSubtitleStore(
|
const resetSubtitleSpecificSettings = useSubtitleStore(
|
||||||
(s) => s.resetSubtitleSpecificSettings,
|
(s) => s.resetSubtitleSpecificSettings,
|
||||||
|
|
@ -21,6 +21,9 @@ export function useCaptions() {
|
||||||
const setCaption = usePlayerStore((s) => s.setCaption);
|
const setCaption = usePlayerStore((s) => s.setCaption);
|
||||||
const currentTranslateTask = usePlayerStore((s) => s.caption.translateTask);
|
const currentTranslateTask = usePlayerStore((s) => s.caption.translateTask);
|
||||||
const lastSelectedLanguage = useSubtitleStore((s) => s.lastSelectedLanguage);
|
const lastSelectedLanguage = useSubtitleStore((s) => s.lastSelectedLanguage);
|
||||||
|
const lastSelectedSubtitleId = useSubtitleStore(
|
||||||
|
(s) => s.lastSelectedSubtitleId,
|
||||||
|
);
|
||||||
const setIsOpenSubtitles = useSubtitleStore((s) => s.setIsOpenSubtitles);
|
const setIsOpenSubtitles = useSubtitleStore((s) => s.setIsOpenSubtitles);
|
||||||
|
|
||||||
const captionList = usePlayerStore((s) => s.captionList);
|
const captionList = usePlayerStore((s) => s.captionList);
|
||||||
|
|
@ -53,7 +56,7 @@ export function useCaptions() {
|
||||||
resetSubtitleSpecificSettings();
|
resetSubtitleSpecificSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
setLanguage(caption.language);
|
setSubtitle(true, caption.language, caption.id);
|
||||||
|
|
||||||
// Use native tracks for MP4 streams instead of custom rendering
|
// Use native tracks for MP4 streams instead of custom rendering
|
||||||
if (source?.type === "file" && enableNativeSubtitles) {
|
if (source?.type === "file" && enableNativeSubtitles) {
|
||||||
|
|
@ -65,7 +68,7 @@ export function useCaptions() {
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
setIsOpenSubtitles,
|
setIsOpenSubtitles,
|
||||||
setLanguage,
|
setSubtitle,
|
||||||
setCaption,
|
setCaption,
|
||||||
resetSubtitleSpecificSettings,
|
resetSubtitleSpecificSettings,
|
||||||
source,
|
source,
|
||||||
|
|
@ -135,14 +138,25 @@ export function useCaptions() {
|
||||||
const disable = useCallback(async () => {
|
const disable = useCallback(async () => {
|
||||||
setIsOpenSubtitles(false);
|
setIsOpenSubtitles(false);
|
||||||
setCaption(null);
|
setCaption(null);
|
||||||
setLanguage(null);
|
setSubtitle(false);
|
||||||
}, [setCaption, setLanguage, setIsOpenSubtitles]);
|
}, [setCaption, setSubtitle, setIsOpenSubtitles]);
|
||||||
|
|
||||||
const selectLastUsedLanguage = useCallback(async () => {
|
const selectLastUsedLanguage = useCallback(async () => {
|
||||||
|
if (lastSelectedSubtitleId) {
|
||||||
|
const caption = captions.find((v) => v.id === lastSelectedSubtitleId);
|
||||||
|
if (caption) return selectCaptionById(caption.id);
|
||||||
|
}
|
||||||
|
|
||||||
const language = lastSelectedLanguage ?? "en";
|
const language = lastSelectedLanguage ?? "en";
|
||||||
await selectLanguage(language);
|
await selectLanguage(language);
|
||||||
return true;
|
return true;
|
||||||
}, [lastSelectedLanguage, selectLanguage]);
|
}, [
|
||||||
|
lastSelectedLanguage,
|
||||||
|
selectLanguage,
|
||||||
|
lastSelectedSubtitleId,
|
||||||
|
captions,
|
||||||
|
selectCaptionById,
|
||||||
|
]);
|
||||||
|
|
||||||
const toggleLastUsed = useCallback(async () => {
|
const toggleLastUsed = useCallback(async () => {
|
||||||
if (enabled) disable();
|
if (enabled) disable();
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,8 @@ export function useInitializeSource() {
|
||||||
);
|
);
|
||||||
const { selectLastUsedLanguageIfEnabled } = useCaptions();
|
const { selectLastUsedLanguageIfEnabled } = useCaptions();
|
||||||
|
|
||||||
// Only select subtitles on initial load, not when source changes
|
|
||||||
const hasInitializedRef = useRef(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (sourceIdentifier && !hasInitializedRef.current) {
|
if (sourceIdentifier) {
|
||||||
hasInitializedRef.current = true;
|
|
||||||
selectLastUsedLanguageIfEnabled();
|
selectLastUsedLanguageIfEnabled();
|
||||||
}
|
}
|
||||||
}, [sourceIdentifier, selectLastUsedLanguageIfEnabled]);
|
}, [sourceIdentifier, selectLastUsedLanguageIfEnabled]);
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ export interface SubtitleStore {
|
||||||
};
|
};
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
lastSelectedLanguage: string | null;
|
lastSelectedLanguage: string | null;
|
||||||
|
lastSelectedSubtitleId: string | null;
|
||||||
isOpenSubtitles: boolean;
|
isOpenSubtitles: boolean;
|
||||||
styling: SubtitleStyling;
|
styling: SubtitleStyling;
|
||||||
overrideCasing: boolean;
|
overrideCasing: boolean;
|
||||||
|
|
@ -66,9 +67,12 @@ export interface SubtitleStore {
|
||||||
showDelayIndicator: boolean;
|
showDelayIndicator: boolean;
|
||||||
updateStyling(newStyling: Partial<SubtitleStyling>): void;
|
updateStyling(newStyling: Partial<SubtitleStyling>): void;
|
||||||
resetStyling(): void;
|
resetStyling(): void;
|
||||||
setLanguage(language: string | null): void;
|
setSubtitle(
|
||||||
|
enabled: boolean,
|
||||||
|
language?: string | null,
|
||||||
|
subtitleId?: string | null,
|
||||||
|
): void;
|
||||||
setIsOpenSubtitles(isOpenSubtitles: boolean): void;
|
setIsOpenSubtitles(isOpenSubtitles: boolean): void;
|
||||||
setCustomSubs(): void;
|
|
||||||
setOverrideCasing(enabled: boolean): void;
|
setOverrideCasing(enabled: boolean): void;
|
||||||
setDelay(delay: number): void;
|
setDelay(delay: number): void;
|
||||||
importSubtitleLanguage(lang: string | null): void;
|
importSubtitleLanguage(lang: string | null): void;
|
||||||
|
|
@ -84,6 +88,7 @@ export const useSubtitleStore = create(
|
||||||
lastSelectedLanguage: null,
|
lastSelectedLanguage: null,
|
||||||
},
|
},
|
||||||
lastSelectedLanguage: null,
|
lastSelectedLanguage: null,
|
||||||
|
lastSelectedSubtitleId: null,
|
||||||
isOpenSubtitles: false,
|
isOpenSubtitles: false,
|
||||||
overrideCasing: false,
|
overrideCasing: false,
|
||||||
delay: 0,
|
delay: 0,
|
||||||
|
|
@ -105,6 +110,11 @@ export const useSubtitleStore = create(
|
||||||
s.overrideCasing = false;
|
s.overrideCasing = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setIsOpenSubtitles(isOpenSubtitles) {
|
||||||
|
set((s) => {
|
||||||
|
s.isOpenSubtitles = isOpenSubtitles;
|
||||||
|
});
|
||||||
|
},
|
||||||
updateStyling(newStyling) {
|
updateStyling(newStyling) {
|
||||||
set((s) => {
|
set((s) => {
|
||||||
if (newStyling.backgroundOpacity !== undefined)
|
if (newStyling.backgroundOpacity !== undefined)
|
||||||
|
|
@ -153,21 +163,16 @@ export const useSubtitleStore = create(
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setLanguage(lang) {
|
setSubtitle(enabled, language, subtitleId) {
|
||||||
set((s) => {
|
set((s) => {
|
||||||
s.enabled = !!lang;
|
s.enabled = enabled;
|
||||||
if (lang) s.lastSelectedLanguage = lang;
|
if (enabled) {
|
||||||
});
|
s.lastSelectedLanguage = language ?? null;
|
||||||
},
|
s.lastSelectedSubtitleId = subtitleId ?? null;
|
||||||
setIsOpenSubtitles(isOpenSubtitles) {
|
} else {
|
||||||
set((s) => {
|
s.lastSelectedLanguage = null;
|
||||||
s.isOpenSubtitles = isOpenSubtitles;
|
s.lastSelectedSubtitleId = null;
|
||||||
});
|
}
|
||||||
},
|
|
||||||
setCustomSubs() {
|
|
||||||
set((s) => {
|
|
||||||
s.enabled = true;
|
|
||||||
s.lastSelectedLanguage = null;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setOverrideCasing(enabled) {
|
setOverrideCasing(enabled) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue