|
|
|
@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
|
|
|
|
|
import { |
|
|
|
|
getCaptionUrl, |
|
|
|
|
convertCustomCaptionFileToWebVTT, |
|
|
|
|
CUSTOM_CAPTION_ID, |
|
|
|
|
parseSubtitles, |
|
|
|
|
subtitleTypeList, |
|
|
|
|
} from "@/backend/helpers/captions"; |
|
|
|
|
import { MWCaption } from "@/backend/helpers/streams"; |
|
|
|
|
import { Icon, Icons } from "@/components/Icon"; |
|
|
|
@ -13,10 +13,11 @@ import { useVideoPlayerDescriptor } from "@/video/state/hooks";
@@ -13,10 +13,11 @@ import { useVideoPlayerDescriptor } from "@/video/state/hooks";
|
|
|
|
|
import { useControls } from "@/video/state/logic/controls"; |
|
|
|
|
import { useMeta } from "@/video/state/logic/meta"; |
|
|
|
|
import { useSource } from "@/video/state/logic/source"; |
|
|
|
|
import { ChangeEvent, useMemo, useRef } from "react"; |
|
|
|
|
import { useMemo, useRef } from "react"; |
|
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
|
import { PopoutListEntry, PopoutSection } from "./PopoutUtils"; |
|
|
|
|
|
|
|
|
|
const customCaption = "external-custom"; |
|
|
|
|
function makeCaptionId(caption: MWCaption, isLinked: boolean): string { |
|
|
|
|
return isLinked ? `linked-${caption.langIso}` : `external-${caption.langIso}`; |
|
|
|
|
} |
|
|
|
@ -41,35 +42,17 @@ export function CaptionSelectionPopout(props: {
@@ -41,35 +42,17 @@ export function CaptionSelectionPopout(props: {
|
|
|
|
|
async (caption: MWCaption, isLinked: boolean) => { |
|
|
|
|
const id = makeCaptionId(caption, isLinked); |
|
|
|
|
loadingId.current = id; |
|
|
|
|
controls.setCaption(id, await getCaptionUrl(caption)); |
|
|
|
|
const blobUrl = await getCaptionUrl(caption); |
|
|
|
|
const result = await fetch(blobUrl); |
|
|
|
|
const text = await result.text(); |
|
|
|
|
parseSubtitles(text); // This will throw if the file is invalid
|
|
|
|
|
controls.setCaption(id, blobUrl); |
|
|
|
|
controls.closePopout(); |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const currentCaption = source.source?.caption?.id; |
|
|
|
|
const customCaptionUploadElement = useRef<HTMLInputElement>(null); |
|
|
|
|
const [setCustomCaption, loadingCustomCaption, errorCustomCaption] = |
|
|
|
|
useLoading(async (captionFile: File) => { |
|
|
|
|
if ( |
|
|
|
|
!captionFile.name.endsWith(".srt") && |
|
|
|
|
!captionFile.name.endsWith(".vtt") |
|
|
|
|
) { |
|
|
|
|
throw new Error("Only SRT or VTT files are allowed"); |
|
|
|
|
} |
|
|
|
|
controls.setCaption( |
|
|
|
|
CUSTOM_CAPTION_ID, |
|
|
|
|
await convertCustomCaptionFileToWebVTT(captionFile) |
|
|
|
|
); |
|
|
|
|
controls.closePopout(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
async function handleUploadCaption(e: ChangeEvent<HTMLInputElement>) { |
|
|
|
|
if (!e.target.files) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
const captionFile = e.target.files[0]; |
|
|
|
|
setCustomCaption(captionFile); |
|
|
|
|
} |
|
|
|
|
return ( |
|
|
|
|
<FloatingView |
|
|
|
|
{...props.router.pageProps(props.prefix)} |
|
|
|
@ -105,23 +88,28 @@ export function CaptionSelectionPopout(props: {
@@ -105,23 +88,28 @@ export function CaptionSelectionPopout(props: {
|
|
|
|
|
{t("videoPlayer.popouts.noCaptions")} |
|
|
|
|
</PopoutListEntry> |
|
|
|
|
<PopoutListEntry |
|
|
|
|
key={CUSTOM_CAPTION_ID} |
|
|
|
|
active={currentCaption === CUSTOM_CAPTION_ID} |
|
|
|
|
loading={loadingCustomCaption} |
|
|
|
|
errored={!!errorCustomCaption} |
|
|
|
|
onClick={() => { |
|
|
|
|
customCaptionUploadElement.current?.click(); |
|
|
|
|
}} |
|
|
|
|
key={customCaption} |
|
|
|
|
active={currentCaption === customCaption} |
|
|
|
|
loading={loading && loadingId.current === customCaption} |
|
|
|
|
errored={error && loadingId.current === customCaption} |
|
|
|
|
onClick={() => customCaptionUploadElement.current?.click()} |
|
|
|
|
> |
|
|
|
|
{currentCaption === CUSTOM_CAPTION_ID |
|
|
|
|
{currentCaption === customCaption |
|
|
|
|
? t("videoPlayer.popouts.customCaption") |
|
|
|
|
: t("videoPlayer.popouts.uploadCustomCaption")} |
|
|
|
|
<input |
|
|
|
|
className="hidden" |
|
|
|
|
ref={customCaptionUploadElement} |
|
|
|
|
accept={subtitleTypeList} |
|
|
|
|
type="file" |
|
|
|
|
onChange={handleUploadCaption} |
|
|
|
|
className="hidden" |
|
|
|
|
accept=".vtt, .srt" |
|
|
|
|
onChange={(e) => { |
|
|
|
|
if (!e.target.files) return; |
|
|
|
|
const customSubtitle = { |
|
|
|
|
langIso: "custom", |
|
|
|
|
url: URL.createObjectURL(e.target.files[0]), |
|
|
|
|
}; |
|
|
|
|
setCaption(customSubtitle, false); |
|
|
|
|
}} |
|
|
|
|
/> |
|
|
|
|
</PopoutListEntry> |
|
|
|
|
</PopoutSection> |
|
|
|
|