From 3c5fb6607384845bf35161d56ce6190fd63de2a9 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sat, 14 Oct 2023 19:28:27 +0200 Subject: [PATCH] add episode selector, fix bug where video doesnt unload properly, move to react helmet async to fix react warning Co-authored-by: Jip Frijlink --- package.json | 2 +- pnpm-lock.yaml | 33 +-- .../components/actions/PageTitleAction.tsx | 2 +- src/components/Overlay.tsx | 2 +- src/components/player/atoms/Episodes.tsx | 203 ++++++++++++++++++ src/components/player/atoms/Settings.tsx | 6 +- src/components/player/atoms/Time.tsx | 26 +-- src/components/player/atoms/index.ts | 1 + src/components/player/display/base.ts | 43 ++-- .../player/display/displayInterface.ts | 2 +- src/components/player/internals/Button.tsx | 18 +- .../player/internals/ContextUtils.tsx | 74 +++++-- .../player/internals/HeadUpdater.tsx | 2 +- .../player/internals/VideoContainer.tsx | 18 +- src/hooks/useOverlayRouter.ts | 35 +-- src/index.tsx | 13 +- src/pages/HomePage.tsx | 2 +- src/pages/PlayerView.tsx | 9 +- src/pages/parts/errors/ErrorWrapperPart.tsx | 2 +- src/pages/parts/player/PlayerPart.tsx | 3 +- src/setup/index.css | 2 +- src/stores/player/slices/display.ts | 2 +- src/stores/player/slices/source.ts | 1 - 23 files changed, 391 insertions(+), 110 deletions(-) create mode 100644 src/components/player/atoms/Episodes.tsx diff --git a/package.json b/package.json index fa2d0283..5a880018 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-ga4": "^2.0.0", - "react-helmet": "^6.1.0", + "react-helmet-async": "^1.3.0", "react-i18next": "^12.1.1", "react-router-dom": "^5.2.0", "react-stickynode": "^4.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05eba9b1..43a2da12 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -80,9 +80,9 @@ dependencies: react-ga4: specifier: ^2.0.0 version: 2.1.0 - react-helmet: - specifier: ^6.1.0 - version: 6.1.0(react@17.0.2) + react-helmet-async: + specifier: ^1.3.0 + version: 1.3.0(react-dom@17.0.2)(react@17.0.2) react-i18next: specifier: ^12.1.1 version: 12.3.1(i18next@22.5.1)(react-dom@17.0.2)(react@17.0.2) @@ -4191,6 +4191,12 @@ packages: side-channel: 1.0.4 dev: true + /invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + dependencies: + loose-envify: 1.4.0 + dev: false + /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: @@ -5219,16 +5225,19 @@ packages: resolution: {integrity: sha512-ZKS7PGNFqqMd3PJ6+C2Jtz/o1iU9ggiy8Y8nUeksgVuvNISbmrQtJiZNvC/TjDsqD0QlU5Wkgs7i+w9+OjHhhQ==} dev: false - /react-helmet@6.1.0(react@17.0.2): - resolution: {integrity: sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==} + /react-helmet-async@1.3.0(react-dom@17.0.2)(react@17.0.2): + resolution: {integrity: sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==} peerDependencies: - react: '>=16.3.0' + react: ^16.6.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 dependencies: - object-assign: 4.1.1 + '@babel/runtime': 7.22.11 + invariant: 2.2.4 prop-types: 15.8.1 react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) react-fast-compare: 3.2.2 - react-side-effect: 2.1.2(react@17.0.2) + shallowequal: 1.1.0 dev: false /react-i18next@12.3.1(i18next@22.5.1)(react-dom@17.0.2)(react@17.0.2): @@ -5295,14 +5304,6 @@ packages: tiny-warning: 1.0.3 dev: false - /react-side-effect@2.1.2(react@17.0.2): - resolution: {integrity: sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==} - peerDependencies: - react: ^16.3.0 || ^17.0.0 || ^18.0.0 - dependencies: - react: 17.0.2 - dev: false - /react-stickynode@4.1.0(react-dom@17.0.2)(react@17.0.2): resolution: {integrity: sha512-zylWgfad75jLfh/gYIayDcDWIDwO4weZrsZqDpjZ/axhF06zRjdCWFBgUr33Pvv2+htKWqPSFksWTyB6aMQ1ZQ==} peerDependencies: diff --git a/src/_oldvideo/components/actions/PageTitleAction.tsx b/src/_oldvideo/components/actions/PageTitleAction.tsx index c471a141..c6c634df 100644 --- a/src/_oldvideo/components/actions/PageTitleAction.tsx +++ b/src/_oldvideo/components/actions/PageTitleAction.tsx @@ -1,4 +1,4 @@ -import { Helmet } from "react-helmet"; +import { Helmet } from "react-helmet-async"; import { useVideoPlayerDescriptor } from "@/_oldvideo/state/hooks"; diff --git a/src/components/Overlay.tsx b/src/components/Overlay.tsx index 2129f68d..8f0dc1e8 100644 --- a/src/components/Overlay.tsx +++ b/src/components/Overlay.tsx @@ -1,4 +1,4 @@ -import { Helmet } from "react-helmet"; +import { Helmet } from "react-helmet-async"; import { Transition } from "@/components/Transition"; diff --git a/src/components/player/atoms/Episodes.tsx b/src/components/player/atoms/Episodes.tsx new file mode 100644 index 00000000..c8c7515b --- /dev/null +++ b/src/components/player/atoms/Episodes.tsx @@ -0,0 +1,203 @@ +import { ReactNode, useCallback, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useAsync } from "react-use"; + +import { getMetaFromId } from "@/backend/metadata/getmeta"; +import { MWMediaType, MWSeasonMeta } from "@/backend/metadata/types/mw"; +import { Icons } from "@/components/Icon"; +import { OverlayAnchor } from "@/components/overlays/OverlayAnchor"; +import { Overlay } from "@/components/overlays/OverlayDisplay"; +import { OverlayPage } from "@/components/overlays/OverlayPage"; +import { OverlayRouter } from "@/components/overlays/OverlayRouter"; +import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta"; +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 CenteredText(props: { children: React.ReactNode }) { + return ( +
+ {props.children} +
+ ); +} + +function useSeasonData(mediaId: string, seasonId: string) { + const [seasons, setSeason] = useState(null); + + const state = useAsync(async () => { + const data = await getMetaFromId(MWMediaType.SERIES, mediaId, seasonId); + if (data?.meta.type !== MWMediaType.SERIES) return null; + setSeason(data.meta.seasons); + return { + season: data.meta.seasonData, + fullData: data, + }; + }, [mediaId, seasonId]); + + return [state, seasons] as const; +} + +function SeasonsView({ + selectedSeason, + setSeason, +}: { + selectedSeason: string; + setSeason: (id: string) => void; +}) { + const meta = usePlayerStore((s) => s.meta); + const [loadingState, seasons] = useSeasonData( + meta?.tmdbId ?? "", + selectedSeason + ); + + let content: ReactNode = null; + if (seasons) { + content = ( + + {seasons?.map((season) => { + return ( + setSeason(season.id)}> + {season.title} + + + ); + })} + + ); + } else if (loadingState.error) + content = Error loading season; + else if (loadingState.loading) + content = Loading...; + + return ( + + {meta?.title} + {content} + + ); +} + +function EpisodesView({ + id, + selectedSeason, + goBack, +}: { + id: string; + selectedSeason: string; + goBack?: () => void; +}) { + const { t } = useTranslation(); + const router = useOverlayRouter(id); + const { setPlayerMeta } = usePlayerMeta(); + const meta = usePlayerStore((s) => s.meta); + const [loadingState] = useSeasonData(meta?.tmdbId ?? "", selectedSeason); + + const playEpisode = useCallback( + (episodeId: string) => { + if (loadingState.value) + setPlayerMeta(loadingState.value.fullData, episodeId); + router.close(); + }, + [setPlayerMeta, loadingState, router] + ); + + let content: ReactNode = null; + if (loadingState.error) + content = Error loading season; + else if (loadingState.loading) + content = Loading...; + else if (loadingState.value) { + content = ( + + {loadingState.value.season.episodes.map((ep) => { + return ( + playEpisode(ep.id)} + active={ep.id === meta?.episode?.tmdbId} + > + +
+ + E{ep.number} + + {ep.title} +
+
+ +
+ ); + })} +
+ ); + } + + return ( + + + {loadingState?.value?.season.title || t("videoPlayer.loading")} + + {content} + + ); +} + +function EpisodesOverlay({ id }: { id: string }) { + const router = useOverlayRouter(id); + const meta = usePlayerStore((s) => s.meta); + const [selectedSeason, setSelectedSeason] = useState( + meta?.season?.tmdbId ?? "" + ); + + const setSeason = useCallback( + (seasonId: string) => { + setSelectedSeason(seasonId); + router.navigate("/episodes"); + }, + [router] + ); + + return ( + + + + + + + router.navigate("/")} + /> + + + + ); +} + +export function Episodes() { + const { t } = useTranslation(); + const router = useOverlayRouter("episodes"); + const setHasOpenOverlay = usePlayerStore((s) => s.setHasOpenOverlay); + const type = usePlayerStore((s) => s.meta?.type); + + useEffect(() => { + setHasOpenOverlay(router.isRouterActive); + }, [setHasOpenOverlay, router.isRouterActive]); + + if (type !== "show") return null; + + return ( + + router.open("/episodes")} + icon={Icons.EPISODES} + > + {t("videoPlayer.buttons.episodes")} + + + + ); +} diff --git a/src/components/player/atoms/Settings.tsx b/src/components/player/atoms/Settings.tsx index 57a677bb..713d3fdb 100644 --- a/src/components/player/atoms/Settings.tsx +++ b/src/components/player/atoms/Settings.tsx @@ -101,7 +101,7 @@ function SettingsOverlay({ id }: { id: string }) { - Video settings + Video settings router.navigate("/quality")}> Quality @@ -119,11 +119,11 @@ function SettingsOverlay({ id }: { id: string }) { - Viewing Experience + Viewing Experience router.navigate("/quality")}> Enable Captions - + Caption settings diff --git a/src/components/player/atoms/Time.tsx b/src/components/player/atoms/Time.tsx index 2ba0a75f..4870aacc 100644 --- a/src/components/player/atoms/Time.tsx +++ b/src/components/player/atoms/Time.tsx @@ -40,22 +40,22 @@ export function Time() { }, }); + const timeString = `${formatSeconds(currentTime, hasHours)} / ${formatSeconds( + duration, + hasHours + )}`; + const timeFinishedString = `${t("videoPlayer.timeLeft", { + timeLeft: formatSeconds( + secondsRemaining, + durationExceedsHour(secondsRemaining) + ), + })} • ${formattedTimeFinished}`; + const child = timeFormat === VideoPlayerTimeFormat.REGULAR ? ( - <> - {formatSeconds(currentTime, hasHours)}{" "} - / {formatSeconds(duration, hasHours)} - + {timeString} ) : ( - <> - {t("videoPlayer.timeLeft", { - timeLeft: formatSeconds( - secondsRemaining, - durationExceedsHour(secondsRemaining) - ), - })}{" "} - • {formattedTimeFinished} - + {timeFinishedString} ); return ( diff --git a/src/components/player/atoms/index.ts b/src/components/player/atoms/index.ts index e54adc08..e72ef50f 100644 --- a/src/components/player/atoms/index.ts +++ b/src/components/player/atoms/index.ts @@ -9,3 +9,4 @@ export * from "./Volume"; export * from "./Title"; export * from "./EpisodeTitle"; export * from "./Settings"; +export * from "./Episodes"; diff --git a/src/components/player/display/base.ts b/src/components/player/display/base.ts index 5b5d93db..859caf35 100644 --- a/src/components/player/display/base.ts +++ b/src/components/player/display/base.ts @@ -29,15 +29,17 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { if (src.type === "hls") { if (!Hls.isSupported()) throw new Error("HLS not supported"); - hls = new Hls({ enableWorker: false }); - hls.on(Hls.Events.ERROR, (event, data) => { - console.error("HLS error", data); - if (data.fatal) { - throw new Error( - `HLS ERROR:${data.error?.message ?? "Something went wrong"}` - ); - } - }); + if (!hls) { + hls = new Hls({ enableWorker: false }); + hls.on(Hls.Events.ERROR, (event, data) => { + console.error("HLS error", data); + if (data.fatal) { + throw new Error( + `HLS ERROR:${data.error?.message ?? "Something went wrong"}` + ); + } + }); + } hls.attachMedia(vid); hls.loadSource(src.url); @@ -77,6 +79,21 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { }); } + function unloadSource() { + if (videoElement) videoElement.removeAttribute("src"); + if (hls) { + hls.destroy(); + hls = null; + } + } + + function destroyVideoElement() { + unloadSource(); + if (videoElement) { + videoElement = null; + } + } + function fullscreenChange() { isFullscreen = !!document.fullscreenElement || // other browsers @@ -88,20 +105,18 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { on, off, destroy: () => { - if (hls) hls.destroy(); - if (videoElement) { - videoElement.src = ""; - videoElement.remove(); - } + destroyVideoElement(); fscreen.removeEventListener("fullscreenchange", fullscreenChange); }, load(newSource) { + if (!newSource) unloadSource(); source = newSource; emit("loading", true); setSource(); }, processVideoElement(video) { + destroyVideoElement(); videoElement = video; setSource(); }, diff --git a/src/components/player/display/displayInterface.ts b/src/components/player/display/displayInterface.ts index 2cb6f5df..5890d937 100644 --- a/src/components/player/display/displayInterface.ts +++ b/src/components/player/display/displayInterface.ts @@ -17,7 +17,7 @@ export type DisplayInterfaceEvents = { export interface DisplayInterface extends Listener { play(): void; pause(): void; - load(source: LoadableSource): void; + load(source: LoadableSource | null): void; processVideoElement(video: HTMLVideoElement): void; processContainerElement(container: HTMLElement): void; toggleFullscreen(): void; diff --git a/src/components/player/internals/Button.tsx b/src/components/player/internals/Button.tsx index e65a3b1e..e182c3c4 100644 --- a/src/components/player/internals/Button.tsx +++ b/src/components/player/internals/Button.tsx @@ -1,3 +1,5 @@ +import classNames from "classnames"; + import { Icon, Icons } from "@/components/Icon"; export function VideoPlayerButton(props: { @@ -12,15 +14,21 @@ export function VideoPlayerButton(props: { diff --git a/src/components/player/internals/ContextUtils.tsx b/src/components/player/internals/ContextUtils.tsx index c163e4c0..d7a80653 100644 --- a/src/components/player/internals/ContextUtils.tsx +++ b/src/components/player/internals/ContextUtils.tsx @@ -3,12 +3,26 @@ import classNames from "classnames"; import { Icon, Icons } from "@/components/Icon"; function Card(props: { children: React.ReactNode }) { - return
{props.children}
; + return ( +
+
+ {props.children} +
+
+ ); } -function Title(props: { children: React.ReactNode }) { +function CardWithScrollable(props: { children: React.ReactNode }) { return ( -

+
+ {props.children} +
+ ); +} + +function SectionTitle(props: { children: React.ReactNode }) { + return ( +

{props.children}

); @@ -18,7 +32,7 @@ function LinkTitle(props: { children: React.ReactNode; textClass?: string }) { return ( @@ -27,16 +41,23 @@ function LinkTitle(props: { children: React.ReactNode; textClass?: string }) { ); } -function Section(props: { children: React.ReactNode }) { - return
{props.children}
; +function Section(props: { children: React.ReactNode; className?: string }) { + return ( +
{props.children}
+ ); } -function Link(props: { onClick?: () => void; children: React.ReactNode }) { +function Link(props: { + onClick?: () => void; + children: React.ReactNode; + active?: boolean; +}) { const classes = classNames( "flex justify-between items-center py-2 pl-3 pr-3 -ml-3 rounded w-full", { "cursor-default": !props.onClick, "hover:bg-video-context-border hover:bg-opacity-10": !!props.onClick, + "bg-video-context-border bg-opacity-10": props.active, } ); const styles = { width: "calc(100% + 1.5rem)" }; @@ -61,25 +82,36 @@ function Link(props: { onClick?: () => void; children: React.ReactNode }) { ); } +function Title(props: { + children: React.ReactNode; + rightSide?: React.ReactNode; +}) { + return ( +
+

+
{props.children}
+
{props.rightSide}
+

+
+ ); +} + function BackLink(props: { onClick?: () => void; children: React.ReactNode; rightSide?: React.ReactNode; }) { return ( -

-
- - {props.children} -
-
{props.rightSide}
-

+ + <button + type="button" + className="-ml-2 p-2 rounded hover:bg-video-context-light hover:bg-opacity-10" + onClick={props.onClick} + > + <Icon className="text-xl" icon={Icons.ARROW_LEFT} /> + </button> + <span className="line-clamp-1 break-all">{props.children}</span> + ); } @@ -124,7 +156,9 @@ function Anchor(props: { children: React.ReactNode; onClick: () => void }) { export const Context = { Card, + CardWithScrollable, Title, + SectionTitle, BackLink, Section, Link, diff --git a/src/components/player/internals/HeadUpdater.tsx b/src/components/player/internals/HeadUpdater.tsx index da62978e..419976d9 100644 --- a/src/components/player/internals/HeadUpdater.tsx +++ b/src/components/player/internals/HeadUpdater.tsx @@ -1,4 +1,4 @@ -import { Helmet } from "react-helmet"; +import { Helmet } from "react-helmet-async"; import { useTranslation } from "react-i18next"; import { usePlayerStore } from "@/stores/player/store"; diff --git a/src/components/player/internals/VideoContainer.tsx b/src/components/player/internals/VideoContainer.tsx index eaa4315f..eef906b9 100644 --- a/src/components/player/internals/VideoContainer.tsx +++ b/src/components/player/internals/VideoContainer.tsx @@ -9,14 +9,24 @@ function useDisplayInterface() { const display = usePlayerStore((s) => s.display); const setDisplay = usePlayerStore((s) => s.setDisplay); + const displayRef = useRef(display); useEffect(() => { - if (!display) { - setDisplay(makeVideoElementDisplayInterface()); + displayRef.current = display; + }, [display]); + + useEffect(() => { + if (!displayRef.current) { + const newDisplay = makeVideoElementDisplayInterface(); + displayRef.current = newDisplay; + setDisplay(newDisplay); } return () => { - if (display) setDisplay(null); + if (displayRef.current) { + displayRef.current = null; + setDisplay(null); + } }; - }, [display, setDisplay]); + }, [setDisplay]); } export function useShouldShowVideoElement() { diff --git a/src/hooks/useOverlayRouter.ts b/src/hooks/useOverlayRouter.ts index a83815c5..e504d084 100644 --- a/src/hooks/useOverlayRouter.ts +++ b/src/hooks/useOverlayRouter.ts @@ -60,23 +60,26 @@ export function useInternalOverlayRouter(id: string) { setTransition(null); }, [setRoute, route, setTransition]); - const open = useCallback(() => { - const anchor = document.getElementById(`__overlayRouter::${id}`); - if (anchor) { - const rect = anchor.getBoundingClientRect(); - setAnchorPoint({ - h: rect.height, - w: rect.width, - x: rect.x, - y: rect.y, - }); - } else { - setAnchorPoint(null); - } + const open = useCallback( + (defaultRoute = "/") => { + const anchor = document.getElementById(`__overlayRouter::${id}`); + if (anchor) { + const rect = anchor.getBoundingClientRect(); + setAnchorPoint({ + h: rect.height, + w: rect.width, + x: rect.x, + y: rect.y, + }); + } else { + setAnchorPoint(null); + } - setTransition(null); - setRoute(`/${id}`); - }, [id, setRoute, setTransition, setAnchorPoint]); + setTransition(null); + setRoute(joinPath(splitPath(defaultRoute, id))); + }, + [id, setRoute, setTransition, setAnchorPoint] + ); return { showBackwardsTransition, diff --git a/src/index.tsx b/src/index.tsx index cdd870ab..2d77bee5 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,6 +2,7 @@ import "core-js/stable"; import React, { Suspense } from "react"; import type { ReactNode } from "react"; import ReactDOM from "react-dom"; +import { HelmetProvider } from "react-helmet-async"; import { BrowserRouter, HashRouter } from "react-router-dom"; import { registerSW } from "virtual:pwa-register"; @@ -48,11 +49,13 @@ function TheRouter(props: { children: ReactNode }) { ReactDOM.render( - - - - - + + + + + + + , document.getElementById("root") diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 672cfbda..c2a6f6e5 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { Helmet } from "react-helmet"; +import { Helmet } from "react-helmet-async"; import { useTranslation } from "react-i18next"; import { WideContainer } from "@/components/layout/WideContainer"; diff --git a/src/pages/PlayerView.tsx b/src/pages/PlayerView.tsx index 5d0d12f2..cea1a60c 100644 --- a/src/pages/PlayerView.tsx +++ b/src/pages/PlayerView.tsx @@ -1,8 +1,7 @@ import { RunOutput } from "@movie-web/providers"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { useParams } from "react-router-dom"; -import { MWStreamType } from "@/backend/helpers/streams"; import { usePlayer } from "@/components/player/hooks/usePlayer"; import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta"; import { convertRunoutputToSource } from "@/components/player/utils/convertRunoutputToSource"; @@ -21,9 +20,13 @@ export function PlayerView() { const { setPlayerMeta, scrapeMedia } = usePlayerMeta(); const [backUrl] = useState("/"); // TODO redirect to search when needed + const lastMedia = useRef(params.media); useEffect(() => { + if (params.media === lastMedia.current) return; + lastMedia.current = params.media; + console.log("resetting"); reset(); - }, [params.media, reset]); + }, [params, reset]); const playAfterScrape = useCallback( (out: RunOutput | null) => { diff --git a/src/pages/parts/errors/ErrorWrapperPart.tsx b/src/pages/parts/errors/ErrorWrapperPart.tsx index 5b2fd9b0..4cf28787 100644 --- a/src/pages/parts/errors/ErrorWrapperPart.tsx +++ b/src/pages/parts/errors/ErrorWrapperPart.tsx @@ -1,5 +1,5 @@ import { ReactNode } from "react"; -import { Helmet } from "react-helmet"; +import { Helmet } from "react-helmet-async"; import { useTranslation } from "react-i18next"; import { VideoPlayerHeader } from "@/_oldvideo/components/parts/VideoPlayerHeader"; diff --git a/src/pages/parts/player/PlayerPart.tsx b/src/pages/parts/player/PlayerPart.tsx index 91d6f5d3..da3064a4 100644 --- a/src/pages/parts/player/PlayerPart.tsx +++ b/src/pages/parts/player/PlayerPart.tsx @@ -63,7 +63,8 @@ export function PlayerPart(props: PlayerPartProps) { {/* Do mobile controls here :) */} -
+
+
diff --git a/src/setup/index.css b/src/setup/index.css index cdaba622..d656ae3e 100644 --- a/src/setup/index.css +++ b/src/setup/index.css @@ -200,7 +200,7 @@ input[type=range].styled-slider.slider-progress::-ms-fill-lower { } ::-webkit-scrollbar-thumb { - background-color: theme("colors.denim-500"); + background-color: theme("colors.video.context.border"); border: 5px solid transparent; border-left: 0; background-clip: content-box; diff --git a/src/stores/player/slices/display.ts b/src/stores/player/slices/display.ts index 5fec4c94..2e2d7c6a 100644 --- a/src/stores/player/slices/display.ts +++ b/src/stores/player/slices/display.ts @@ -81,7 +81,7 @@ export const createDisplaySlice: MakeSlice = (set, get) => ({ }); }, reset() { - get().display?.destroy(); + get().display?.load(null); set((s) => { s.status = playerStatus.IDLE; s.meta = null; diff --git a/src/stores/player/slices/source.ts b/src/stores/player/slices/source.ts index a8f38aa4..23857e02 100644 --- a/src/stores/player/slices/source.ts +++ b/src/stores/player/slices/source.ts @@ -2,7 +2,6 @@ import { ScrapeMedia } from "@movie-web/providers"; import { MakeSlice } from "@/stores/player/slices/types"; import { - LoadableSource, SourceQuality, SourceSliceSource, selectQuality,