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" ? ( ) : 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 ( <> ); }