diff --git a/index.html b/index.html index 5c674b2f..8ab66908 100644 --- a/index.html +++ b/index.html @@ -19,7 +19,7 @@ diff --git a/src/components/overlays/OverlayPage.tsx b/src/components/overlays/OverlayPage.tsx index af4c7d03..db582395 100644 --- a/src/components/overlays/OverlayPage.tsx +++ b/src/components/overlays/OverlayPage.tsx @@ -44,10 +44,7 @@ export function OverlayPage(props: Props) { show={show} >
- {props.children} + + + + + {props.children} + + ); } diff --git a/src/components/player/atoms/Settings.tsx b/src/components/player/atoms/Settings.tsx index 7f372767..1556a2de 100644 --- a/src/components/player/atoms/Settings.tsx +++ b/src/components/player/atoms/Settings.tsx @@ -6,15 +6,41 @@ import { Overlay } from "@/components/overlays/OverlayDisplay"; import { OverlayPage } from "@/components/overlays/OverlayPage"; import { OverlayRouter } from "@/components/overlays/OverlayRouter"; import { VideoPlayerButton } from "@/components/player/internals/Button"; +import { Context } from "@/components/player/internals/ContextUtils"; import { useOverlayRouter } from "@/hooks/useOverlayRouter"; import { usePlayerStore } from "@/stores/player/store"; function SettingsOverlay({ id }: { id: string }) { + const router = useOverlayRouter("settings"); + return ( - -

This is settings menu, welcome!

+ + + Ba ba ba ba my title + + Hi + router.navigate("/other")}> + Go to page 2 + + + + Video source + SuperStream + + + + + + + Some other bit + + + +
diff --git a/src/components/player/base/BackLink.tsx b/src/components/player/base/BackLink.tsx index 56f97044..27e0255d 100644 --- a/src/components/player/base/BackLink.tsx +++ b/src/components/player/base/BackLink.tsx @@ -1,16 +1,16 @@ import { useTranslation } from "react-i18next"; +import { useHistory } from "react-router-dom"; import { Icon, Icons } from "@/components/Icon"; -import { useGoBack } from "@/hooks/useGoBack"; -export function BackLink() { +export function BackLink(props: { url: string }) { const { t } = useTranslation(); - const goBack = useGoBack(); + const history = useHistory(); return (
goBack()} + onClick={() => history.push(props.url)} className="flex items-center cursor-pointer text-type-secondary hover:text-white transition-colors duration-200 font-medium" > diff --git a/src/components/player/hooks/usePlayer.ts b/src/components/player/hooks/usePlayer.ts index 8da2664c..02e3801f 100644 --- a/src/components/player/hooks/usePlayer.ts +++ b/src/components/player/hooks/usePlayer.ts @@ -13,9 +13,11 @@ export function usePlayer() { const setMeta = usePlayerStore((s) => s.setMeta); const status = usePlayerStore((s) => s.status); const display = usePlayerStore((s) => s.display); + const reset = usePlayerStore((s) => s.reset); const { init } = useInitializePlayer(); return { + reset, status, setMeta(meta: PlayerMeta) { setMeta(meta); diff --git a/src/components/player/internals/ContextUtils.tsx b/src/components/player/internals/ContextUtils.tsx new file mode 100644 index 00000000..1aa460b1 --- /dev/null +++ b/src/components/player/internals/ContextUtils.tsx @@ -0,0 +1,56 @@ +import { Icon, Icons } from "@/components/Icon"; + +function Card(props: { children: React.ReactNode }) { + return
{props.children}
; +} + +function Title(props: { children: React.ReactNode }) { + return ( +

+ {props.children} +

+ ); +} + +function Section(props: { children: React.ReactNode }) { + return
{props.children}
; +} + +function Link(props: { onClick?: () => void; children: React.ReactNode }) { + return ( + + ); +} + +function LinkTitle(props: { children: React.ReactNode }) { + return ( + + {props.children} + + ); +} + +function LinkChevron(props: { children?: React.ReactNode }) { + return ( + + {props.children} + + + ); +} + +export const Context = { + Card, + Title, + Section, + Link, + LinkTitle, + LinkChevron, +}; diff --git a/src/hooks/useOverlayRouter.ts b/src/hooks/useOverlayRouter.ts index 046156de..a83815c5 100644 --- a/src/hooks/useOverlayRouter.ts +++ b/src/hooks/useOverlayRouter.ts @@ -56,9 +56,9 @@ export function useInternalOverlayRouter(id: string) { } const close = useCallback(() => { + if (route) setRoute(null); setTransition(null); - setRoute(null); - }, [setRoute, setTransition]); + }, [setRoute, route, setTransition]); const open = useCallback(() => { const anchor = document.getElementById(`__overlayRouter::${id}`); diff --git a/src/pages/PlayerView.tsx b/src/pages/PlayerView.tsx index a73d5cca..7d6b8067 100644 --- a/src/pages/PlayerView.tsx +++ b/src/pages/PlayerView.tsx @@ -1,13 +1,11 @@ import { RunOutput } from "@movie-web/providers"; -import { useCallback } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useParams } from "react-router-dom"; -import { useAsync } from "react-use"; import { MWStreamType } from "@/backend/helpers/streams"; -import { getMetaFromId } from "@/backend/metadata/getmeta"; -import { decodeTMDBId } from "@/backend/metadata/tmdb"; import { usePlayer } from "@/components/player/hooks/usePlayer"; import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta"; +import { MetaPart } from "@/pages/parts/player/MetaPart"; import { PlayerPart } from "@/pages/parts/player/PlayerPart"; import { ScrapingPart } from "@/pages/parts/player/ScrapingPart"; import { playerStatus } from "@/stores/player/slices/source"; @@ -18,18 +16,13 @@ export function PlayerView() { episode?: string; season?: string; }>(); - const { status, playMedia } = usePlayer(); + const { status, playMedia, reset } = usePlayer(); const { setPlayerMeta, scrapeMedia } = usePlayerMeta(); + const [backUrl] = useState("/"); - const { loading, error } = useAsync(async () => { - const data = decodeTMDBId(params.media); - if (!data) return; - - const meta = await getMetaFromId(data.type, data.id, params.season); - if (!meta) return; - - setPlayerMeta(meta); - }, []); + useEffect(() => { + reset(); + }, [params.media, reset]); const playAfterScrape = useCallback( (out: RunOutput | null) => { @@ -57,12 +50,9 @@ export function PlayerView() { ); return ( - + {status === playerStatus.IDLE ? ( -
- {loading ?

loading meta...

: null} - {error ?

failed to load meta!

: null} -
+ ) : null} {status === playerStatus.SCRAPING && scrapeMedia ? ( diff --git a/src/pages/parts/player/MetaPart.tsx b/src/pages/parts/player/MetaPart.tsx new file mode 100644 index 00000000..9efdc0dd --- /dev/null +++ b/src/pages/parts/player/MetaPart.tsx @@ -0,0 +1,54 @@ +import { useHistory, useParams } from "react-router-dom"; +import { useAsync } from "react-use"; + +import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta"; +import { decodeTMDBId } from "@/backend/metadata/tmdb"; +import { MWMediaType } from "@/backend/metadata/types/mw"; + +export interface MetaPartProps { + onGetMeta?: (meta: DetailedMeta, episodeId?: string) => void; +} + +export function MetaPart(props: MetaPartProps) { + const params = useParams<{ + media: string; + episode?: string; + season?: string; + }>(); + const history = useHistory(); + + const { loading, error } = useAsync(async () => { + const data = decodeTMDBId(params.media); + if (!data) return; + + const meta = await getMetaFromId(data.type, data.id, params.season); + if (!meta) return; + + // replace link with new link if youre not already on the right link + let epId = params.episode; + if (meta.meta.type === MWMediaType.SERIES) { + let ep = meta.meta.seasonData.episodes.find( + (v) => v.id === params.episode + ); + if (!ep) ep = meta.meta.seasonData.episodes[0]; + epId = ep.id; + if ( + params.season !== meta.meta.seasonData.id || + params.episode !== ep.id + ) { + history.replace( + `/media/${params.media}/${meta.meta.seasonData.id}/${ep.id}` + ); + } + } + + props.onGetMeta?.(meta, epId); + }, []); + + return ( +
+ {loading ?

loading meta...

: null} + {error ?

failed to load meta!

: null} +
+ ); +} diff --git a/src/pages/parts/player/PlayerPart.tsx b/src/pages/parts/player/PlayerPart.tsx index 62092009..91d6f5d3 100644 --- a/src/pages/parts/player/PlayerPart.tsx +++ b/src/pages/parts/player/PlayerPart.tsx @@ -6,6 +6,7 @@ import { useShouldShowControls } from "@/components/player/hooks/useShouldShowCo export interface PlayerPartProps { children?: ReactNode; + backUrl: string; onLoad?: () => void; } @@ -34,7 +35,7 @@ export function PlayerPart(props: PlayerPartProps) {
- + / diff --git a/src/setup/App.tsx b/src/setup/App.tsx index 840b612b..4d063fa5 100644 --- a/src/setup/App.tsx +++ b/src/setup/App.tsx @@ -67,13 +67,18 @@ function App() { - + {({ match }) => { if (match?.params.query) - return ; - return ; + return ( + + ); + return ; }} diff --git a/src/stores/player/slices/display.ts b/src/stores/player/slices/display.ts index bb2645bd..e2ced531 100644 --- a/src/stores/player/slices/display.ts +++ b/src/stores/player/slices/display.ts @@ -1,9 +1,11 @@ import { DisplayInterface } from "@/components/player/display/displayInterface"; +import { playerStatus } from "@/stores/player/slices/source"; import { MakeSlice } from "@/stores/player/slices/types"; export interface DisplaySlice { display: DisplayInterface | null; setDisplay(display: DisplayInterface | null): void; + reset(): void; } export const createDisplaySlice: MakeSlice = (set, get) => ({ @@ -68,4 +70,11 @@ export const createDisplaySlice: MakeSlice = (set, get) => ({ s.display = newDisplay; }); }, + reset() { + get().display?.destroy(); + set((s) => { + s.status = playerStatus.IDLE; + s.meta = null; + }); + }, }); diff --git a/tailwind.config.js b/tailwind.config.js index ff9650a7..d2eb0a07 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -123,6 +123,17 @@ module.exports = { audio: { set: "#A75FC9" + }, + + context: { + background: "#0C1216", + light: "#4D79A8", + border: "#4F5C66", + + type: { + main: "#617A8A", + secondary: "#374A56" + } } } }