|
|
|
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
|
|
|
|
import Fuse from "fuse.js"; |
|
|
|
|
import { useMemo, useRef, useState } from "react"; |
|
|
|
|
import { type DragEvent, useMemo, useRef, useState } from "react"; |
|
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
|
import { useAsyncFn } from "react-use"; |
|
|
|
|
import { convert } from "subsrt-ts"; |
|
|
|
@ -7,6 +7,7 @@ import { convert } from "subsrt-ts";
@@ -7,6 +7,7 @@ import { convert } from "subsrt-ts";
|
|
|
|
|
import { subtitleTypeList } from "@/backend/helpers/subs"; |
|
|
|
|
import { FileDropHandler } from "@/components/DropFile"; |
|
|
|
|
import { FlagIcon } from "@/components/FlagIcon"; |
|
|
|
|
import { Icon, Icons } from "@/components/Icon"; |
|
|
|
|
import { useCaptions } from "@/components/player/hooks/useCaptions"; |
|
|
|
|
import { Menu } from "@/components/player/internals/ContextMenu"; |
|
|
|
|
import { Input } from "@/components/player/internals/ContextMenu/Input"; |
|
|
|
@ -127,6 +128,32 @@ export function CaptionsView({ id }: { id: string }) {
@@ -127,6 +128,32 @@ export function CaptionsView({ id }: { id: string }) {
|
|
|
|
|
const [dragging, setDragging] = useState(false); |
|
|
|
|
const setCaption = usePlayerStore((s) => s.setCaption); |
|
|
|
|
|
|
|
|
|
function onDrop(event: DragEvent<HTMLDivElement>) { |
|
|
|
|
const files = event.dataTransfer.files; |
|
|
|
|
const firstFile = files[0]; |
|
|
|
|
if (!files || !firstFile) return; |
|
|
|
|
|
|
|
|
|
const fileExtension = `.${firstFile.name.split(".").pop()}`; |
|
|
|
|
if (!fileExtension || !subtitleTypeList.includes(fileExtension)) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const reader = new FileReader(); |
|
|
|
|
reader.addEventListener("load", (e) => { |
|
|
|
|
if (!e.target || typeof e.target.result !== "string") return; |
|
|
|
|
|
|
|
|
|
const converted = convert(e.target.result, "srt"); |
|
|
|
|
|
|
|
|
|
setCaption({ |
|
|
|
|
language: "custom", |
|
|
|
|
srtData: converted, |
|
|
|
|
id: "custom-caption", |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
reader.readAsText(firstFile); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const captions = useMemo( |
|
|
|
|
() => |
|
|
|
|
captionList.length !== 0 ? captionList : getHlsCaptionList?.() ?? [], |
|
|
|
@ -165,32 +192,19 @@ export function CaptionsView({ id }: { id: string }) {
@@ -165,32 +192,19 @@ export function CaptionsView({ id }: { id: string }) {
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<FileDropHandler |
|
|
|
|
className={`transition duration-300 ${dragging ? "brightness-50" : ""}`} |
|
|
|
|
onDraggingChange={(isDragging) => { |
|
|
|
|
setDragging(isDragging); |
|
|
|
|
}} |
|
|
|
|
onDrop={(event) => { |
|
|
|
|
const files = event.dataTransfer.files; |
|
|
|
|
if (!files || files.length === 0) return; |
|
|
|
|
|
|
|
|
|
const reader = new FileReader(); |
|
|
|
|
reader.addEventListener("load", (e) => { |
|
|
|
|
if (!e.target || typeof e.target.result !== "string") return; |
|
|
|
|
|
|
|
|
|
const converted = convert(e.target.result, "srt"); |
|
|
|
|
|
|
|
|
|
setCaption({ |
|
|
|
|
language: "custom", |
|
|
|
|
srtData: converted, |
|
|
|
|
id: "custom-caption", |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
reader.readAsText(files[0]); |
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
<> |
|
|
|
|
<div> |
|
|
|
|
{dragging && ( |
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center text-white z-10 pointer-events-none"> |
|
|
|
|
<div className="flex flex-col items-center"> |
|
|
|
|
<Icon className="text-4xl mb-8" icon={Icons.FILE} /> |
|
|
|
|
<span className="text-xl"> |
|
|
|
|
{t("player.menus.subtitles.dropSubtitleFile")} |
|
|
|
|
</span> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
<Menu.BackLink |
|
|
|
|
onClick={() => router.navigate("/")} |
|
|
|
|
rightSide={ |
|
|
|
@ -205,19 +219,29 @@ export function CaptionsView({ id }: { id: string }) {
@@ -205,19 +219,29 @@ export function CaptionsView({ id }: { id: string }) {
|
|
|
|
|
> |
|
|
|
|
{t("player.menus.subtitles.title")} |
|
|
|
|
</Menu.BackLink> |
|
|
|
|
</div> |
|
|
|
|
<FileDropHandler |
|
|
|
|
className={`transition duration-300 ${dragging ? "brightness-50" : ""}`} |
|
|
|
|
onDraggingChange={(isDragging) => { |
|
|
|
|
setDragging(isDragging); |
|
|
|
|
}} |
|
|
|
|
onDrop={(event) => onDrop(event)} |
|
|
|
|
> |
|
|
|
|
<div className="mt-3"> |
|
|
|
|
<Input value={searchQuery} onInput={setSearchQuery} /> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<Menu.ScrollToActiveSection className="!pt-1 mt-2 pb-3"> |
|
|
|
|
<CaptionOption onClick={() => disable()} selected={!selectedCaptionId}> |
|
|
|
|
{t("player.menus.subtitles.offChoice")} |
|
|
|
|
</CaptionOption> |
|
|
|
|
<CustomCaptionOption /> |
|
|
|
|
{content} |
|
|
|
|
</Menu.ScrollToActiveSection> |
|
|
|
|
</FileDropHandler> |
|
|
|
|
<Menu.ScrollToActiveSection className="!pt-1 mt-2 pb-3"> |
|
|
|
|
<CaptionOption |
|
|
|
|
onClick={() => disable()} |
|
|
|
|
selected={!selectedCaptionId} |
|
|
|
|
> |
|
|
|
|
{t("player.menus.subtitles.offChoice")} |
|
|
|
|
</CaptionOption> |
|
|
|
|
<CustomCaptionOption /> |
|
|
|
|
{content} |
|
|
|
|
</Menu.ScrollToActiveSection> |
|
|
|
|
</FileDropHandler> |
|
|
|
|
</> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|