import { useCallback, useMemo } from "react";
import { Trans, useTranslation } from "react-i18next";
import { useCopyToClipboard } from "react-use";
import { downloadCaption } from "@/backend/helpers/subs";
import { Button } from "@/components/buttons/Button";
import { Icon, Icons } from "@/components/Icon";
import { OverlayPage } from "@/components/overlays/OverlayPage";
import { Menu } from "@/components/player/internals/ContextMenu";
import { convertSubtitlesToSrtDataurl } from "@/components/player/utils/captions";
import { useIsDesktopApp } from "@/hooks/useIsDesktopApp";
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
import { usePlayerStore } from "@/stores/player/store";
export function useDownloadLink() {
const source = usePlayerStore((s) => s.source);
const currentQuality = usePlayerStore((s) => s.currentQuality);
const url = useMemo(() => {
if (source?.type === "file") {
const quality = currentQuality
? source.qualities[currentQuality]
: undefined;
if (quality) return quality.url;
// Fallback to the first available quality if currentQuality is not set
const firstQuality = Object.values(source.qualities)[0];
return firstQuality?.url;
}
if (source?.type === "hls") return source.url;
return undefined;
}, [source, currentQuality]);
return url;
}
function StyleTrans(props: { k: string }) {
return (
,
br:
,
ios_share: (
),
ios_files: (
),
}}
/>
);
}
export function DownloadView({ id }: { id: string }) {
const router = useOverlayRouter(id);
const { t } = useTranslation();
const downloadUrl = useDownloadLink();
// Custom function to process the download URL
const processDownloadUrl = useCallback(() => {
if (!downloadUrl) return "";
// Check if the URL contains the m3u8-proxy and the ?url= parameter
const match = downloadUrl.match(/m3u8-proxy\?url=(.*)$/);
if (match && match[1]) {
// Decode the URL component
return decodeURIComponent(match[1]);
}
return downloadUrl; // Return original if no specific pattern is found
}, [downloadUrl]);
const hlsDownload = `https://hls-downloader.pstream.mov/?url=${encodeURIComponent(processDownloadUrl())}`;
const [, copyToClipboard] = useCopyToClipboard();
const sourceType = usePlayerStore((s) => s.source?.type);
const selectedCaption = usePlayerStore((s) => s.caption?.selected);
const captionList = usePlayerStore((s) => s.captionList);
const meta = usePlayerStore((s) => s.meta);
const duration = usePlayerStore((s) => s.progress.duration);
const source = usePlayerStore((s) => s.source);
const isDesktopApp = useIsDesktopApp();
const startOfflineDownload = useCallback(async () => {
if (!downloadUrl) return;
const title = meta?.title ? meta.title : t("player.menus.downloads.title");
const poster = meta?.poster;
let subtitleText: string | undefined;
if (selectedCaption?.srtData) {
subtitleText = selectedCaption.srtData;
} else if (captionList.length > 0) {
// Auto-fetch the first English caption, or the first available one
const defaultCaption =
captionList.find((c) => c.language === "en") ?? captionList[0];
try {
subtitleText = await downloadCaption(defaultCaption);
} catch {
// Continue without subtitles if fetch fails
}
}
const headers = {
...(source?.headers ?? {}),
...(source?.preferredHeaders ?? {}),
};
window.desktopApi?.startDownload({
url: downloadUrl,
title,
poster,
subtitleText,
duration,
type: sourceType,
headers,
});
if (window.desktopApi?.openOffline) {
window.desktopApi.openOffline();
} else {
router.navigate("/");
}
}, [
downloadUrl,
meta,
selectedCaption,
captionList,
duration,
router,
source,
sourceType,
t,
]);
const openSubtitleDownload = useCallback(() => {
const dataUrl = selectedCaption
? convertSubtitlesToSrtDataurl(selectedCaption?.srtData)
: null;
if (!dataUrl) return;
window.open(dataUrl);
}, [selectedCaption]);
return (
<>
router.navigate("/")}>
{t("player.menus.downloads.title")}
{sourceType === "hls" ? (
{isDesktopApp ? (
<>
>
) : (
<>
>
)}
) : sourceType === "file" ? (
{isDesktopApp ? (
<>
>
) : (
<>
router.navigate("/download/pc")}
>
{t("player.menus.downloads.onPc.title")}
router.navigate("/download/ios")}
>
{t("player.menus.downloads.onIos.title")}
router.navigate("/download/android")}
>
{t("player.menus.downloads.onAndroid.title")}
>
)}
) : (
<>
router.navigate("/download/pc")}>
{t("player.menus.downloads.onPc.title")}
router.navigate("/download/ios")}
>
{t("player.menus.downloads.onIos.title")}
router.navigate("/download/android")}
>
{t("player.menus.downloads.onAndroid.title")}
>
)}
>
);
}
function AndroidExplanationView({ id }: { id: string }) {
const router = useOverlayRouter(id);
const { t } = useTranslation();
return (
<>
router.navigate("/download")}>
{t("player.menus.downloads.onAndroid.shortTitle")}
>
);
}
function PCExplanationView({ id }: { id: string }) {
const router = useOverlayRouter(id);
const { t } = useTranslation();
return (
<>
router.navigate("/download")}>
{t("player.menus.downloads.onPc.shortTitle")}
>
);
}
function IOSExplanationView({ id }: { id: string }) {
const router = useOverlayRouter(id);
return (
<>
router.navigate("/download")}>
>
);
}
export function DownloadRoutes({ id }: { id: string }) {
return (
<>
>
);
}