diff --git a/public/config.js b/public/config.js index 9ffc51ab..eb936081 100644 --- a/public/config.js +++ b/public/config.js @@ -3,5 +3,5 @@ window.__CONFIG__ = { VITE_CORS_PROXY_URL: "", VITE_TMDB_API_KEY: "b030404650f279792a8d3287232358e3", - VITE_OMDB_API_KEY: "aa0937c0" + VITE_OMDB_API_KEY: "aa0937c0", }; diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index bf0a0ae2..71d5095e 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -34,6 +34,7 @@ export enum Icons { CAPTIONS = "captions", LINK = "link", CASTING = "casting", + DOWNLOAD = "download", } export interface IconProps { @@ -75,6 +76,7 @@ const iconList: Record = { captions: ``, link: ``, casting: "", + download: ``, }; function ChromeCastButton() { diff --git a/src/setup/locales/en/translation.json b/src/setup/locales/en/translation.json index 14bb2845..9989fe2d 100644 --- a/src/setup/locales/en/translation.json +++ b/src/setup/locales/en/translation.json @@ -60,7 +60,8 @@ "buttons": { "episodes": "Episodes", "source": "Source", - "captions": "Captions" + "captions": "Captions", + "download": "Download" }, "popouts": { "sources": "Sources", diff --git a/src/utils/normalizeTitle.ts b/src/utils/normalizeTitle.ts new file mode 100644 index 00000000..f21a7edb --- /dev/null +++ b/src/utils/normalizeTitle.ts @@ -0,0 +1,7 @@ +export function normalizeTitle(title: string): string { + return title + .trim() + .toLowerCase() + .replace(/['":]/g, "") + .replace(/[^a-zA-Z0-9]+/g, "_"); +} diff --git a/src/utils/titleMatch.ts b/src/utils/titleMatch.ts index dfdf3883..5be7be94 100644 --- a/src/utils/titleMatch.ts +++ b/src/utils/titleMatch.ts @@ -1,10 +1,4 @@ -function normalizeTitle(title: string): string { - return title - .trim() - .toLowerCase() - .replace(/['":]/g, "") - .replace(/[^a-zA-Z0-9]+/g, "_"); -} +import { normalizeTitle } from "./normalizeTitle"; export function compareTitle(a: string, b: string): boolean { return normalizeTitle(a) === normalizeTitle(b); diff --git a/src/video/components/VideoPlayer.tsx b/src/video/components/VideoPlayer.tsx index 688f42e2..ef774b20 100644 --- a/src/video/components/VideoPlayer.tsx +++ b/src/video/components/VideoPlayer.tsx @@ -30,6 +30,7 @@ import { ReactNode, useCallback, useState } from "react"; import { PopoutProviderAction } from "@/video/components/popouts/PopoutProviderAction"; import { ChromecastAction } from "@/video/components/actions/ChromecastAction"; import { CastingTextAction } from "@/video/components/actions/CastingTextAction"; +import { DownloadAction } from "@/video/components/actions/DownloadAction"; type Props = VideoPlayerBaseProps; @@ -141,6 +142,7 @@ export function VideoPlayer(props: Props) {
+ @@ -157,6 +159,7 @@ export function VideoPlayer(props: Props) {
+ diff --git a/src/video/components/actions/DownloadAction.tsx b/src/video/components/actions/DownloadAction.tsx new file mode 100644 index 00000000..10d59ce5 --- /dev/null +++ b/src/video/components/actions/DownloadAction.tsx @@ -0,0 +1,41 @@ +import { Icons } from "@/components/Icon"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useSource } from "@/video/state/logic/source"; +import { MWStreamType } from "@/backend/helpers/streams"; +import { normalizeTitle } from "@/utils/normalizeTitle"; +import { useIsMobile } from "@/hooks/useIsMobile"; +import { useTranslation } from "react-i18next"; +import { useMeta } from "@/video/state/logic/meta"; +import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; + +interface Props { + className?: string; +} + +export function DownloadAction(props: Props) { + const descriptor = useVideoPlayerDescriptor(); + const sourceInterface = useSource(descriptor); + const { isMobile } = useIsMobile(); + const { t } = useTranslation(); + const meta = useMeta(descriptor); + + const isHLS = sourceInterface.source?.type === MWStreamType.HLS; + + const title = meta?.meta.meta.title; + + return ( + + + + ); +} diff --git a/src/video/components/parts/VideoPlayerIconButton.tsx b/src/video/components/parts/VideoPlayerIconButton.tsx index 8755d72d..e75a4673 100644 --- a/src/video/components/parts/VideoPlayerIconButton.tsx +++ b/src/video/components/parts/VideoPlayerIconButton.tsx @@ -10,6 +10,7 @@ export interface VideoPlayerIconButtonProps { active?: boolean; wide?: boolean; noPadding?: boolean; + disabled?: boolean; } export const VideoPlayerIconButton = forwardRef< @@ -21,13 +22,21 @@ export const VideoPlayerIconButton = forwardRef<