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" && currentQuality) return source.qualities[currentQuality]?.url ?? null; if (source?.type === "hls") return source.url; return null; }, [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 isDesktopApp = useIsDesktopApp(); const startOfflineDownload = useCallback(async () => { if (!downloadUrl) return; const title = meta?.title ? meta.title : "Video"; 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 } } window.desktopApi?.startDownload({ url: downloadUrl, title, poster, subtitleText, duration, type: sourceType, }); if (window.desktopApi?.openOffline) { window.desktopApi.openOffline(); } else { router.navigate("/"); } }, [ downloadUrl, meta, selectedCaption, captionList, duration, router, sourceType, ]); const openSubtitleDownload = useCallback(() => { const dataUrl = selectedCaption ? convertSubtitlesToSrtDataurl(selectedCaption?.srtData) : null; if (!dataUrl) return; window.open(dataUrl); }, [selectedCaption]); if (!downloadUrl) return null; return ( <> router.navigate("/")}> {t("player.menus.downloads.title")}
{sourceType === "hls" ? (
{isDesktopApp ? ( <> Download this video directly to your app for offline playback. ) : ( <>

)}
) : sourceType === "file" ? (
{isDesktopApp ? ( <> Download this video directly to your app for offline playback. ) : ( )}
) : ( <> 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 ( <> ); }