mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-10-31 10:37:13 -04:00 
			
		
		
		
	Use rnv v7 for the rework
This commit is contained in:
		
							parent
							
								
									ebbed77650
								
							
						
					
					
						commit
						02c77d2f32
					
				| @ -1,73 +0,0 @@ | |||||||
| { |  | ||||||
| 	"name": "mobile", |  | ||||||
| 	"version": "1.0.0", |  | ||||||
| 	"main": "expo-router/entry", |  | ||||||
| 	"sideEffects": false, |  | ||||||
| 	"scripts": { |  | ||||||
| 		"dev": "expo start", |  | ||||||
| 		"android": "expo run:android", |  | ||||||
| 		"ios": "expo run:ios", |  | ||||||
| 		"web": "expo start --web", |  | ||||||
| 		"build": "eas build --profile production --platform android --non-interactive --auto-submit", |  | ||||||
| 		"build:apk": "eas build --profile preview --platform android --non-interactive --json", |  | ||||||
| 		"build:dev": "eas build --profile development --platform android --non-interactive", |  | ||||||
| 		"update": "eas update --auto --channel prod" |  | ||||||
| 	}, |  | ||||||
| 	"dependencies": { |  | ||||||
| 		"@expo-google-fonts/poppins": "^0.2.3", |  | ||||||
| 		"@formatjs/intl-displaynames": "^6.6.8", |  | ||||||
| 		"@formatjs/intl-locale": "^4.0.0", |  | ||||||
| 		"@gorhom/portal": "^1.0.14", |  | ||||||
| 		"@kesha-antonov/react-native-background-downloader": "^3.2.0", |  | ||||||
| 		"@kyoo/ui": "workspace:^", |  | ||||||
| 		"@material-symbols/svg-400": "^0.22.0", |  | ||||||
| 		"@react-native-community/netinfo": "11.3.2", |  | ||||||
| 		"@shopify/flash-list": "1.7.1", |  | ||||||
| 		"@tanstack/query-sync-storage-persister": "^5.51.21", |  | ||||||
| 		"@tanstack/react-query": "^5.51.23", |  | ||||||
| 		"@tanstack/react-query-persist-client": "^5.51.23", |  | ||||||
| 		"array-shuffle": "^3.0.0", |  | ||||||
| 		"babel-plugin-transform-inline-environment-variables": "^0.4.4", |  | ||||||
| 		"expo": "^51.0.26", |  | ||||||
| 		"expo-build-properties": "~0.12.5", |  | ||||||
| 		"expo-constants": "~16.0.2", |  | ||||||
| 		"expo-dev-client": "~4.0.22", |  | ||||||
| 		"expo-file-system": "~17.0.1", |  | ||||||
| 		"expo-font": "~12.0.9", |  | ||||||
| 		"expo-image-picker": "~15.0.7", |  | ||||||
| 		"expo-linear-gradient": "~13.0.2", |  | ||||||
| 		"expo-linking": "~6.3.1", |  | ||||||
| 		"expo-localization": "~15.0.3", |  | ||||||
| 		"expo-navigation-bar": "~3.0.7", |  | ||||||
| 		"expo-router": "3.5.21", |  | ||||||
| 		"expo-screen-orientation": "~7.0.5", |  | ||||||
| 		"expo-secure-store": "~13.0.2", |  | ||||||
| 		"expo-status-bar": "~1.12.1", |  | ||||||
| 		"expo-updates": "~0.25.22", |  | ||||||
| 		"i18next": "^23.12.2", |  | ||||||
| 		"intl-pluralrules": "^2.0.1", |  | ||||||
| 		"moti": "^0.29.0", |  | ||||||
| 		"react": "18.3.1", |  | ||||||
| 		"react-i18next": "^15.0.1", |  | ||||||
| 		"react-native": "0.74.5", |  | ||||||
| 		"react-native-blurhash": "^2.0.3", |  | ||||||
| 		"react-native-fast-image": "^8.6.3", |  | ||||||
| 		"react-native-mmkv": "^2.12.2", |  | ||||||
| 		"react-native-reanimated": "~3.15.0", |  | ||||||
| 		"react-native-safe-area-context": "4.10.8", |  | ||||||
| 		"react-native-screens": "3.34.0", |  | ||||||
| 		"react-native-svg": "15.2.0", |  | ||||||
| 		"react-native-uuid": "^2.0.2", |  | ||||||
| 		"react-native-video": "^6.4.3", |  | ||||||
| 		"yoshiki": "1.2.14" |  | ||||||
| 	}, |  | ||||||
| 	"devDependencies": { |  | ||||||
| 		"@babel/core": "^7.25.2", |  | ||||||
| 		"react-native-svg-transformer": "^1.5.0", |  | ||||||
| 		"typescript": "~5.5.4" |  | ||||||
| 	}, |  | ||||||
| 	"installConfig": { |  | ||||||
| 		"hoistingLimits": "workspaces" |  | ||||||
| 	}, |  | ||||||
| 	"private": true |  | ||||||
| } |  | ||||||
| @ -1,60 +0,0 @@ | |||||||
| { |  | ||||||
| 	"name": "web", |  | ||||||
| 	"version": "0.1.0", |  | ||||||
| 	"private": true, |  | ||||||
| 	"sideEffects": ["./src/polyfill.ts"], |  | ||||||
| 	"scripts": { |  | ||||||
| 		"dev": "next dev", |  | ||||||
| 		"build": "next build", |  | ||||||
| 		"start": "next start", |  | ||||||
| 		"lint": "next lint", |  | ||||||
| 		"format": "prettier --check --ignore-path .gitignore '!src/utils/jotai-utils.tsx' .", |  | ||||||
| 		"format:fix": "prettier --write --ignore-path .gitignore '!src/utils/jotai-utils.tsx' ." |  | ||||||
| 	}, |  | ||||||
| 	"dependencies": { |  | ||||||
| 		"@gorhom/portal": "^1.0.14", |  | ||||||
| 		"@kyoo/models": "workspace:^", |  | ||||||
| 		"@kyoo/primitives": "workspace:^", |  | ||||||
| 		"@kyoo/ui": "workspace:^", |  | ||||||
| 		"@material-symbols/svg-400": "^0.22.0", |  | ||||||
| 		"@radix-ui/react-dropdown-menu": "^2.1.1", |  | ||||||
| 		"@radix-ui/react-select": "^2.1.1", |  | ||||||
| 		"@tanstack/react-query": "^5.51.23", |  | ||||||
| 		"@tanstack/react-query-devtools": "^5.51.23", |  | ||||||
| 		"array-shuffle": "^3.0.0", |  | ||||||
| 		"expo-image-picker": "~15.0.7", |  | ||||||
| 		"expo-linear-gradient": "^13.0.2", |  | ||||||
| 		"expo-modules-core": "^1.12.20", |  | ||||||
| 		"hls.js": "^1.5.14", |  | ||||||
| 		"i18next": "^23.12.2", |  | ||||||
| 		"jassub": "1.7.15", |  | ||||||
| 		"jotai": "^2.9.2", |  | ||||||
| 		"moti": "^0.29.0", |  | ||||||
| 		"next": "14.2.5", |  | ||||||
| 		"next-translate": "^2.6.2", |  | ||||||
| 		"raf": "^3.4.1", |  | ||||||
| 		"react": "18.3.1", |  | ||||||
| 		"react-dom": "18.3.1", |  | ||||||
| 		"react-i18next": "^15.0.1", |  | ||||||
| 		"react-native-reanimated": "3.15.0", |  | ||||||
| 		"react-native-svg": "15.2.0", |  | ||||||
| 		"react-native-video": "^6.4.3", |  | ||||||
| 		"react-native-web": "0.19.12", |  | ||||||
| 		"react-tooltip": "^5.28.0", |  | ||||||
| 		"solito": "^4.2.2", |  | ||||||
| 		"srt-webvtt": "zoriya/srt-webvtt#build", |  | ||||||
| 		"superjson": "^2.2.1", |  | ||||||
| 		"sweetalert2": "^11.12.4", |  | ||||||
| 		"yoshiki": "1.2.14", |  | ||||||
| 		"zod": "^3.23.8" |  | ||||||
| 	}, |  | ||||||
| 	"devDependencies": { |  | ||||||
| 		"@svgr/webpack": "^8.1.0", |  | ||||||
| 		"@types/node": "22.2.0", |  | ||||||
| 		"@types/react-dom": "18.3.0", |  | ||||||
| 		"copy-webpack-plugin": "^12.0.2", |  | ||||||
| 		"react-native": "0.74.5", |  | ||||||
| 		"typescript": "^5.5.4", |  | ||||||
| 		"webpack": "^5.93.0" |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										963
									
								
								front/bun.lock
									
									
									
									
									
								
							
							
						
						
									
										963
									
								
								front/bun.lock
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -33,7 +33,6 @@ | |||||||
| 		"expo-status-bar": "~2.2.3", | 		"expo-status-bar": "~2.2.3", | ||||||
| 		"expo-updates": "~0.28.14", | 		"expo-updates": "~0.28.14", | ||||||
| 		"i18next-http-backend": "^3.0.2", | 		"i18next-http-backend": "^3.0.2", | ||||||
| 		"jotai": "^2.12.5", |  | ||||||
| 		"react": "19.0.0", | 		"react": "19.0.0", | ||||||
| 		"react-i18next": "^15.5.2", | 		"react-i18next": "^15.5.2", | ||||||
| 		"react-native": "0.79.3", | 		"react-native": "0.79.3", | ||||||
| @ -42,7 +41,7 @@ | |||||||
| 		"react-native-safe-area-context": "5.4.0", | 		"react-native-safe-area-context": "5.4.0", | ||||||
| 		"react-native-screens": "~4.11.1", | 		"react-native-screens": "~4.11.1", | ||||||
| 		"react-native-svg": "15.11.2", | 		"react-native-svg": "15.11.2", | ||||||
| 		"react-native-video": "^6.15.0", | 		"react-native-video": "^7.0.0-alpha.1", | ||||||
| 		"react-native-web": "^0.20.0", | 		"react-native-web": "^0.20.0", | ||||||
| 		"react-tooltip": "^5.29.1", | 		"react-tooltip": "^5.29.1", | ||||||
| 		"sweetalert2": "^11.22.0", | 		"sweetalert2": "^11.22.0", | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| import { z } from "zod/v4"; | import { z } from "zod/v4"; | ||||||
| import { Entry } from "./entry"; | import { Entry } from "./entry"; | ||||||
| import { Extra } from "./extra"; | import { Extra } from "./extra"; | ||||||
|  | import { Show } from "./show"; | ||||||
| import { zdate } from "./utils/utils"; | import { zdate } from "./utils/utils"; | ||||||
| 
 | 
 | ||||||
| export const Video = z.object({ | export const Video = z.object({ | ||||||
| @ -36,9 +37,16 @@ export const Video = z.object({ | |||||||
| 
 | 
 | ||||||
| export const FullVideo = Video.extend({ | export const FullVideo = Video.extend({ | ||||||
| 	slugs: z.array(z.string()), | 	slugs: z.array(z.string()), | ||||||
|  | 	progress: z.object({ | ||||||
|  | 		percent: z.int().min(0).max(100), | ||||||
|  | 		time: z.int().min(0).nullable(), | ||||||
|  | 		playedDate: zdate().nullable(), | ||||||
|  | 		videoId: z.string().nullable(), | ||||||
|  | 	}), | ||||||
| 	entries: z.array(Entry), | 	entries: z.array(Entry), | ||||||
| 	previous: z.object({ video: z.string(), entry: Entry }).nullable().optional(), | 	previous: z.object({ video: z.string(), entry: Entry }).nullable().optional(), | ||||||
| 	next: z.object({ video: z.string(), entry: Entry }).nullable().optional(), | 	next: z.object({ video: z.string(), entry: Entry }).nullable().optional(), | ||||||
|  | 	show: Show.optional(), | ||||||
| }); | }); | ||||||
| export type FullVideo = z.infer<typeof FullVideo>; | export type FullVideo = z.infer<typeof FullVideo>; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -62,3 +62,16 @@ export const readValue = <T extends ZodType>(key: string, parser: T) => { | |||||||
| 	if (val === undefined) return val; | 	if (val === undefined) return val; | ||||||
| 	return parser.parse(JSON.parse(val)) as z.infer<T>; | 	return parser.parse(JSON.parse(val)) as z.infer<T>; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export const useLocalSetting = <T extends string>(setting: string, def: T) => { | ||||||
|  | 	if (Platform.OS === "web" && typeof window === "undefined") | ||||||
|  | 		return [def as T, null!] as const; | ||||||
|  | 	// biome-ignore lint/correctness/useHookAtTopLevel: ssr
 | ||||||
|  | 	const [val, setter] = useMMKVString(`settings.${setting}`, storage); | ||||||
|  | 	return [(val ?? def) as T, setter] as const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const getLocalSetting = (setting: string, def: string) => { | ||||||
|  | 	if (Platform.OS === "web" && typeof window === "undefined") return def; | ||||||
|  | 	return storage.getString(`settings.${setting}`) ?? setting; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -1,184 +1,115 @@ | |||||||
| import { useSetAtom } from "jotai"; | import { Stack } from "expo-router"; | ||||||
| import { type ComponentProps, useEffect, useState } from "react"; | import { StyleSheet, View } from "react-native"; | ||||||
| import { useTranslation } from "react-i18next"; | import { useVideoPlayer, VideoView } from "react-native-video"; | ||||||
| import { Platform, StyleSheet, View } from "react-native"; | import { entryDisplayNumber } from "~/components/entries"; | ||||||
| import { useYoshiki } from "yoshiki/native"; | import { FullVideo, VideoInfo } from "~/models"; | ||||||
| import { type Episode, FullVideo, type Movie, VideoInfo } from "~/models"; |  | ||||||
| import { Head } from "~/primitives"; | import { Head } from "~/primitives"; | ||||||
| import type { QueryIdentifier } from "~/query"; | import { useToken } from "~/providers/account-context"; | ||||||
| import { Back, Hover, LoadingIndicator } from "./components/hover"; | import { useLocalSetting } from "~/providers/settings"; | ||||||
| import { useVideoKeyboard } from "./keyboard"; | import { type QueryIdentifier, useFetch } from "~/query"; | ||||||
| import { durationAtom, fullscreenAtom, Video } from "./state"; | import { useQueryState } from "~/utils"; | ||||||
| import { WatchStatusObserver } from "./watch-status-observer"; |  | ||||||
| 
 | 
 | ||||||
| type Item = (Movie & { type: "movie" }) | (Episode & { type: "episode" }); | // import { Hover, LoadingIndicator } from "./components/hover";
 | ||||||
|  | // import { useVideoKeyboard } from "./keyboard";
 | ||||||
|  | // import { durationAtom, fullscreenAtom, Video } from "./state";
 | ||||||
|  | 
 | ||||||
|  | const mapMetadata = (item: FullVideo | undefined) => { | ||||||
|  | 	if (!item) return null; | ||||||
|  | 
 | ||||||
|  | 	// TODO: map current entry using entries' duration & the current playtime
 | ||||||
|  | 	const currentEntry = 0; | ||||||
|  | 	const entry = item.entries[currentEntry] ?? item.entries[0]; | ||||||
|  | 	if (!entry) return null; | ||||||
| 
 | 
 | ||||||
| const mapData = ( |  | ||||||
| 	data: Item | undefined, |  | ||||||
| 	info: WatchInfo | undefined, |  | ||||||
| 	previousSlug?: string, |  | ||||||
| 	nextSlug?: string, |  | ||||||
| ): Partial<ComponentProps<typeof Hover>> & { isLoading: boolean } => { |  | ||||||
| 	if (!data) return { isLoading: true }; |  | ||||||
| 	return { | 	return { | ||||||
| 		isLoading: false, | 		currentEntry, | ||||||
| 		name: | 		title: `${entry.name} (${entryDisplayNumber(entry)})`, | ||||||
| 			data.type === "movie" | 		description: entry.description, | ||||||
| 				? data.name | 		subtitle: item.show!.kind !== "movie" ? item.show!.name : null, | ||||||
| 				: `${episodeDisplayNumber(data)} ${data.name}`, | 		poster: item.show!.poster, | ||||||
| 		showName: data.type === "movie" ? data.name! : data.show!.name, | 		thumbnail: item.show!.thumbnail, | ||||||
| 		poster: data.type === "movie" ? data.poster : data.show!.poster, |  | ||||||
| 		subtitles: info?.subtitles, |  | ||||||
| 		audios: info?.audios, |  | ||||||
| 		chapters: info?.chapters, |  | ||||||
| 		fonts: info?.fonts, |  | ||||||
| 		previousSlug, |  | ||||||
| 		nextSlug, |  | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const formatTitleMetadata = (item: Item) => { | export const Player = () => { | ||||||
| 	if (item.type === "movie") { | 	const [slug] = useQueryState("slug", undefined!); | ||||||
| 		return item.name; |  | ||||||
| 	} |  | ||||||
| 	return `${item.name} (${episodeDisplayNumber({ |  | ||||||
| 		seasonNumber: item.seasonNumber, |  | ||||||
| 		episodeNumber: item.episodeNumber, |  | ||||||
| 		absoluteNumber: item.absoluteNumber, |  | ||||||
| 	})})`;
 |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| export const Player = ({ | 	const { apiUrl, authToken } = useToken(); | ||||||
| 	slug, | 	const [playMode] = useLocalSetting<"direct" | "hls">("playMode", "direct"); | ||||||
| 	type, | 	const player = useVideoPlayer({ | ||||||
| 	t: startTimeP, | 		uri: `${apiUrl}/api/videos/${slug}/${playMode === "direct" ? "direct" : "master.m3u8"}`, | ||||||
| }: { | 		headers: { | ||||||
| 	slug: string; | 			Authorization: `Bearer ${authToken}`, | ||||||
| 	type: "episode" | "movie"; | 		}, | ||||||
| 	t?: number; | 	}); | ||||||
| }) => { |  | ||||||
| 	const { css } = useYoshiki(); |  | ||||||
| 	const { t } = useTranslation(); |  | ||||||
| 	const router = useRouter(); |  | ||||||
| 
 | 
 | ||||||
| 	const [playbackError, setPlaybackError] = useState<string | undefined>( | 	const { data, error } = useFetch(Player.query(slug)); | ||||||
| 		undefined, | 	const { data: info, error: infoError } = useFetch(Player.infoQuery(slug)); | ||||||
| 	); | 	const metadata = mapMetadata(data); | ||||||
| 	const { data, error } = useFetch(Player.query(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; |  | ||||||
| 	const previous = |  | ||||||
| 		data && data.type === "episode" && data.previousEpisode |  | ||||||
| 			? `/watch/${data.previousEpisode.slug}?t=0` |  | ||||||
| 			: undefined; |  | ||||||
| 	const next = |  | ||||||
| 		data && data.type === "episode" && data.nextEpisode |  | ||||||
| 			? `/watch/${data.nextEpisode.slug}?t=0` |  | ||||||
| 			: undefined; |  | ||||||
| 	const title = data && formatTitleMetadata(data); |  | ||||||
| 	const subtitle = |  | ||||||
| 		data && data.type === "episode" ? data.show?.name : undefined; |  | ||||||
| 
 | 
 | ||||||
| 	useVideoKeyboard(info?.subtitles, info?.fonts, previous, next); | 	// const [playbackError, setPlaybackError] = useState<string | undefined>(
 | ||||||
|  | 	// 	undefined,
 | ||||||
|  | 	// );
 | ||||||
|  | 	// useVideoKeyboard(info?.subtitles, info?.fonts, previous, next);
 | ||||||
| 
 | 
 | ||||||
| 	const startTime = startTimeP ?? data?.watchStatus?.watchedTime; | 	// const startTime = startTimeP ?? data?.watchStatus?.watchedTime;
 | ||||||
| 
 | 
 | ||||||
| 	const setFullscreen = useSetAtom(fullscreenAtom); | 	// const setFullscreen = useSetAtom(fullscreenAtom);
 | ||||||
| 	useEffect(() => { | 	// useEffect(() => {
 | ||||||
| 		if (Platform.OS !== "web") return; | 	// 	if (Platform.OS !== "web") return;
 | ||||||
| 		if (/Mobi/i.test(window.navigator.userAgent)) setFullscreen(true); | 	// 	if (/Mobi/i.test(window.navigator.userAgent)) setFullscreen(true);
 | ||||||
| 		return () => { | 	// 	return () => {
 | ||||||
| 			if (!document.location.href.includes("/watch")) setFullscreen(false); | 	// 		if (!document.location.href.includes("/watch")) setFullscreen(false);
 | ||||||
| 		}; | 	// 	};
 | ||||||
| 	}, [setFullscreen]); | 	// }, [setFullscreen]);
 | ||||||
| 
 | 
 | ||||||
| 	const setDuration = useSetAtom(durationAtom); | 	// if (error || infoError || playbackError)
 | ||||||
| 	useEffect(() => { | 	// 	return (
 | ||||||
| 		setDuration(info?.durationSeconds); | 	// 		<>
 | ||||||
| 	}, [info, setDuration]); | 	// 			<Back
 | ||||||
| 
 | 	// 				isLoading={false}
 | ||||||
| 	if (error || infoError || playbackError) | 	// 				{...css({ position: "relative", bg: (theme) => theme.accent })}
 | ||||||
| 		return ( | 	// 			/>
 | ||||||
| 			<> | 	// 			<ErrorView error={error ?? infoError ?? { errors: [playbackError!] }} />
 | ||||||
| 				<Back | 	// 		</>
 | ||||||
| 					isLoading={false} | 	// 	);
 | ||||||
| 					{...css({ position: "relative", bg: (theme) => theme.accent })} |  | ||||||
| 				/> |  | ||||||
| 				<ErrorView error={error ?? infoError ?? { errors: [playbackError!] }} /> |  | ||||||
| 			</> |  | ||||||
| 		); |  | ||||||
| 
 | 
 | ||||||
| 	return ( | 	return ( | ||||||
| 		<> |  | ||||||
| 			<Head title={title} description={data?.overview} /> |  | ||||||
| 			{data && info && ( |  | ||||||
| 				<WatchStatusObserver |  | ||||||
| 					type={type} |  | ||||||
| 					slug={data.slug} |  | ||||||
| 					duration={info.durationSeconds} |  | ||||||
| 				/> |  | ||||||
| 			)} |  | ||||||
| 		<View | 		<View | ||||||
| 				{...css({ | 			style={{ | ||||||
| 					flexGrow: 1, | 				flex: 1, | ||||||
| 					flexShrink: 1, | 				backgroundColor: "black", | ||||||
| 					bg: "black", | 			}} | ||||||
| 				})} |  | ||||||
| 		> | 		> | ||||||
| 				<Video | 			<Head | ||||||
| 					metadata={{ | 				title={metadata?.title} | ||||||
| 						title: title ?? t("show.episodeNoMetadata"), | 				description={metadata?.description} | ||||||
| 						artist: subtitle ?? undefined, | 				image={metadata?.thumbnail?.high} | ||||||
| 						description: data?.overview ?? undefined, |  | ||||||
| 						imageUri: image?.medium, |  | ||||||
| 						next: next, |  | ||||||
| 						previous: previous, |  | ||||||
| 					}} |  | ||||||
| 					links={data?.links} |  | ||||||
| 					audios={info?.audios} |  | ||||||
| 					subtitles={info?.subtitles} |  | ||||||
| 					codec={info?.mimeCodec} |  | ||||||
| 					setError={setPlaybackError} |  | ||||||
| 					fonts={info?.fonts} |  | ||||||
| 					startTime={startTime} |  | ||||||
| 					onEnd={() => { |  | ||||||
| 						if (!data) return; |  | ||||||
| 						if (data.type === "movie") |  | ||||||
| 							router.replace(`/movie/${data.slug}`, undefined, { |  | ||||||
| 								experimental: { |  | ||||||
| 									nativeBehavior: "stack-replace", |  | ||||||
| 									isNestedNavigator: true, |  | ||||||
| 								}, |  | ||||||
| 							}); |  | ||||||
| 						else |  | ||||||
| 							router.replace(next ?? `/show/${data.show!.slug}`, undefined, { |  | ||||||
| 								experimental: { |  | ||||||
| 									nativeBehavior: "stack-replace", |  | ||||||
| 									isNestedNavigator: true, |  | ||||||
| 								}, |  | ||||||
| 							}); |  | ||||||
| 					}} |  | ||||||
| 					{...css(StyleSheet.absoluteFillObject)} |  | ||||||
| 			/> | 			/> | ||||||
| 				<LoadingIndicator /> | 			<Stack.Screen | ||||||
| 				<Hover | 				options={{ | ||||||
| 					{...mapData(data, info, previous, next)} | 					// TODO: find a way to force fullscreen on mobile
 | ||||||
| 					url={`${type}/${slug}`} | 					headerTransparent: true, | ||||||
|  | 					headerStyle: { backgroundColor: undefined }, | ||||||
|  | 				}} | ||||||
| 			/> | 			/> | ||||||
|  | 			<VideoView | ||||||
|  | 				player={player} | ||||||
|  | 				pictureInPicture={true} | ||||||
|  | 				autoEnterPictureInPicture={true} | ||||||
|  | 				resizeMode={"contain"} | ||||||
|  | 				style={StyleSheet.absoluteFillObject} | ||||||
|  | 			/> | ||||||
|  | 			{/* <LoadingIndicator /> */} | ||||||
|  | 			{/* <Hover {...mapData(data, info, previous, next)} url={`${type}/${slug}`} /> */} | ||||||
| 		</View> | 		</View> | ||||||
| 		</> |  | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Player.query = (slug: string): QueryIdentifier<FullVideo> => ({ | Player.query = (slug: string): QueryIdentifier<FullVideo> => ({ | ||||||
| 	path: ["api", "videos", slug], | 	path: ["api", "videos", slug], | ||||||
| 	params: { | 	params: { | ||||||
| 		fields: ["next", "previous", "serie"], | 		fields: ["next", "previous", "show"], | ||||||
| 	}, | 	}, | ||||||
| 	parser: FullVideo, | 	parser: FullVideo, | ||||||
| }); | }); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user