From a0739e57f28ad964a5f9dd3ee34dfb32f79a31f9 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sat, 19 Jul 2025 18:17:48 +0200 Subject: [PATCH] Init player rework --- front/packages/ui/src/downloads/index.web.tsx | 2 +- front/packages/ui/src/downloads/state.tsx | 2 +- front/src/app/(app)/watch/[slug].tsx | 3 + front/src/ui/details/header.tsx | 51 ++++---- .../ui}/player/components/hover.tsx | 0 .../ui}/player/components/left-buttons.tsx | 0 .../ui}/player/components/right-buttons.tsx | 2 +- .../ui}/player/components/scrubber.tsx | 2 +- .../ui/src => src/ui}/player/index.tsx | 109 +++++++++--------- .../ui/src => src/ui}/player/keyboard.tsx | 0 .../src => src/ui}/player/media-session.tsx | 0 .../ui/src => src/ui}/player/state.tsx | 0 .../ui/src => src/ui}/player/video.tsx | 2 +- .../ui/src => src/ui}/player/video.web.tsx | 2 +- .../ui}/player/watch-status-observer.tsx | 0 15 files changed, 90 insertions(+), 85 deletions(-) create mode 100644 front/src/app/(app)/watch/[slug].tsx rename front/{packages/ui/src => src/ui}/player/components/hover.tsx (100%) rename front/{packages/ui/src => src/ui}/player/components/left-buttons.tsx (100%) rename front/{packages/ui/src => src/ui}/player/components/right-buttons.tsx (98%) rename front/{packages/ui/src => src/ui}/player/components/scrubber.tsx (99%) rename front/{packages/ui/src => src/ui}/player/index.tsx (63%) rename front/{packages/ui/src => src/ui}/player/keyboard.tsx (100%) rename front/{packages/ui/src => src/ui}/player/media-session.tsx (100%) rename front/{packages/ui/src => src/ui}/player/state.tsx (100%) rename front/{packages/ui/src => src/ui}/player/video.tsx (98%) rename front/{packages/ui/src => src/ui}/player/video.web.tsx (99%) rename front/{packages/ui/src => src/ui}/player/watch-status-observer.tsx (100%) diff --git a/front/packages/ui/src/downloads/index.web.tsx b/front/packages/ui/src/downloads/index.web.tsx index b85ce946..d31c8dd2 100644 --- a/front/packages/ui/src/downloads/index.web.tsx +++ b/front/packages/ui/src/downloads/index.web.tsx @@ -21,7 +21,7 @@ import { type WatchInfo, getCurrentApiUrl, queryFn, toQueryKey } from "@kyoo/models"; import { getCurrentAccount } from "@kyoo/models/src/account-internal"; import type { ReactNode } from "react"; -import { Player } from "../player"; +import { Player } from "../../../../src/ui/player../src/ui/player"; export const useDownloader = () => { return async (type: "episode" | "movie", slug: string) => { diff --git a/front/packages/ui/src/downloads/state.tsx b/front/packages/ui/src/downloads/state.tsx index c1d8b503..d8fd4482 100644 --- a/front/packages/ui/src/downloads/state.tsx +++ b/front/packages/ui/src/downloads/state.tsx @@ -41,7 +41,7 @@ import { type PrimitiveAtom, atom, useSetAtom, useStore } from "jotai"; import { type ReactNode, useEffect } from "react"; import { ToastAndroid } from "react-native"; import { z } from "zod"; -import { Player } from "../player"; +import { Player } from "../../../../src/ui/player"; type Router = ReturnType; diff --git a/front/src/app/(app)/watch/[slug].tsx b/front/src/app/(app)/watch/[slug].tsx new file mode 100644 index 00000000..16a4237f --- /dev/null +++ b/front/src/app/(app)/watch/[slug].tsx @@ -0,0 +1,3 @@ +import { Player } from "~/ui/player"; + +export default Player; diff --git a/front/src/ui/details/header.tsx b/front/src/ui/details/header.tsx index c2875a94..584d0fb5 100644 --- a/front/src/ui/details/header.tsx +++ b/front/src/ui/details/header.tsx @@ -35,6 +35,7 @@ import { A, Chip, Container, + ContrastArea, capitalize, DottedSeparator, GradientImageBackground, @@ -714,30 +715,32 @@ export const Header = ({ }, }) as any)} /> - + + + . - */ - -import { - type Episode, - EpisodeP, - type Movie, - MovieP, - type QueryIdentifier, - type WatchInfo, - WatchInfoP, - useFetch, -} from "@kyoo/models"; -import { Head } from "@kyoo/primitives"; import { useSetAtom } from "jotai"; import { type ComponentProps, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { Platform, StyleSheet, View } from "react-native"; -import { useRouter } from "solito/router"; import { useYoshiki } from "yoshiki/native"; -import { episodeDisplayNumber } from "../../../../src/ui/details/episode"; -import { ErrorView } from "../../../../src/ui/errors"; +import { + Episode, + Movie, + type QueryIdentifier, + useFetch, + type WatchInfo, + WatchInfoP, +} from "~/models"; +import { Head } from "~/primitives"; import { Back, Hover, LoadingIndicator } from "./components/hover"; import { useVideoKeyboard } from "./keyboard"; -import { Video, durationAtom, fullscreenAtom } from "./state"; +import { durationAtom, fullscreenAtom, Video } from "./state"; import { WatchStatusObserver } from "./watch-status-observer"; type Item = (Movie & { type: "movie" }) | (Episode & { type: "episode" }); @@ -53,7 +28,10 @@ const mapData = ( if (!data) return { isLoading: true }; return { isLoading: false, - name: data.type === "movie" ? data.name : `${episodeDisplayNumber(data)} ${data.name}`, + name: + data.type === "movie" + ? data.name + : `${episodeDisplayNumber(data)} ${data.name}`, showName: data.type === "movie" ? data.name! : data.show!.name, poster: data.type === "movie" ? data.poster : data.show!.poster, subtitles: info?.subtitles, @@ -89,11 +67,17 @@ export const Player = ({ const { t } = useTranslation(); const router = useRouter(); - const [playbackError, setPlaybackError] = useState(undefined); + const [playbackError, setPlaybackError] = useState( + undefined, + ); const { data, error } = useFetch(Player.query(type, slug)); - const { data: info, error: infoError } = useFetch(Player.infoQuery(type, slug)); + const { data: info, error: infoError } = useFetch( + Player.infoQuery(type, slug), + ); const image = - data && data.type === "episode" ? (data.show?.poster ?? data?.poster) : data?.poster; + data && data.type === "episode" + ? (data.show?.poster ?? data?.poster) + : data?.poster; const previous = data && data.type === "episode" && data.previousEpisode ? `/watch/${data.previousEpisode.slug}?t=0` @@ -103,7 +87,8 @@ export const Player = ({ ? `/watch/${data.nextEpisode.slug}?t=0` : undefined; const title = data && formatTitleMetadata(data); - const subtitle = data && data.type === "episode" ? data.show?.name : undefined; + const subtitle = + data && data.type === "episode" ? data.show?.name : undefined; useVideoKeyboard(info?.subtitles, info?.fonts, previous, next); @@ -126,7 +111,10 @@ export const Player = ({ if (error || infoError || playbackError) return ( <> - theme.accent })} /> + theme.accent })} + /> ); @@ -135,7 +123,11 @@ export const Player = ({ <> {data && info && ( - + )} - + ); }; -Player.query = (type: "episode" | "movie", slug: string): QueryIdentifier => +Player.query = ( + type: "episode" | "movie", + slug: string, +): QueryIdentifier => type === "episode" ? { path: ["episode", slug], @@ -197,15 +201,10 @@ Player.query = (type: "episode" | "movie", slug: string): QueryIdentifier parser: MovieP.transform((x) => ({ ...x, type: "movie" })), }; -Player.infoQuery = (type: "episode" | "movie", slug: string): QueryIdentifier => ({ +Player.infoQuery = ( + type: "episode" | "movie", + slug: string, +): QueryIdentifier => ({ path: [type, slug, "info"], parser: WatchInfoP, }); - -// if more queries are needed, dont forget to update download.tsx to cache those. -Player.getFetchUrls = ({ slug, type }: { slug: string; type: "episode" | "movie" }) => [ - Player.query(type, slug), - Player.infoQuery(type, slug), -]; - -Player.requiredPermissions = ["overall.play"]; diff --git a/front/packages/ui/src/player/keyboard.tsx b/front/src/ui/player/keyboard.tsx similarity index 100% rename from front/packages/ui/src/player/keyboard.tsx rename to front/src/ui/player/keyboard.tsx diff --git a/front/packages/ui/src/player/media-session.tsx b/front/src/ui/player/media-session.tsx similarity index 100% rename from front/packages/ui/src/player/media-session.tsx rename to front/src/ui/player/media-session.tsx diff --git a/front/packages/ui/src/player/state.tsx b/front/src/ui/player/state.tsx similarity index 100% rename from front/packages/ui/src/player/state.tsx rename to front/src/ui/player/state.tsx diff --git a/front/packages/ui/src/player/video.tsx b/front/src/ui/player/video.tsx similarity index 98% rename from front/packages/ui/src/player/video.tsx rename to front/src/ui/player/video.tsx index 71714fa8..3ce3e985 100644 --- a/front/packages/ui/src/player/video.tsx +++ b/front/src/ui/player/video.tsx @@ -50,7 +50,7 @@ import NativeVideo, { SelectedVideoTrackType, } from "react-native-video"; import { useYoshiki } from "yoshiki/native"; -import { useDisplayName } from "../utils"; +import { useDisplayName } from "../../../packages/ui/src/utils"; import { PlayMode, audioAtom, playModeAtom, subtitleAtom } from "./state"; const MimeTypes: Map = new Map([ diff --git a/front/packages/ui/src/player/video.web.tsx b/front/src/ui/player/video.web.tsx similarity index 99% rename from front/packages/ui/src/player/video.web.tsx rename to front/src/ui/player/video.web.tsx index 05617a29..60be3f20 100644 --- a/front/packages/ui/src/player/video.web.tsx +++ b/front/src/ui/player/video.web.tsx @@ -36,7 +36,7 @@ import { useTranslation } from "react-i18next"; import type { VideoProps } from "react-native-video"; import toVttBlob from "srt-webvtt"; import { useForceRerender, useYoshiki } from "yoshiki"; -import { useDisplayName } from "../utils"; +import { useDisplayName } from "../../../packages/ui/src/utils"; import { MediaSessionManager } from "./media-session"; import { PlayMode, audioAtom, playAtom, playModeAtom, progressAtom, subtitleAtom } from "./state"; diff --git a/front/packages/ui/src/player/watch-status-observer.tsx b/front/src/ui/player/watch-status-observer.tsx similarity index 100% rename from front/packages/ui/src/player/watch-status-observer.tsx rename to front/src/ui/player/watch-status-observer.tsx