mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-08-07 09:01:29 -04:00
Fix player controls style
This commit is contained in:
parent
a52807c565
commit
8e060f0c55
@ -27,9 +27,10 @@ export const Video = z.object({
|
|||||||
|
|
||||||
// Name of the tool that made the guess
|
// Name of the tool that made the guess
|
||||||
from: z.string(),
|
from: z.string(),
|
||||||
get history() {
|
// Adding that results in an infinite recursion
|
||||||
return z.array(Video.shape.guess.omit({ history: true })).default([]);
|
// get history() {
|
||||||
},
|
// return z.array(Video.shape.guess.omit({ history: true })).default([]);
|
||||||
|
// },
|
||||||
}),
|
}),
|
||||||
createdAt: zdate(),
|
createdAt: zdate(),
|
||||||
updatedAt: zdate(),
|
updatedAt: zdate(),
|
||||||
|
@ -25,7 +25,7 @@ export const ImageBackground = ({
|
|||||||
layout: ImageLayout;
|
layout: ImageLayout;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const { css } = useYoshiki();
|
const { css, theme } = useYoshiki();
|
||||||
const { apiUrl, authToken } = useToken();
|
const { apiUrl, authToken } = useToken();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -42,7 +42,10 @@ export const ImageBackground = ({
|
|||||||
}}
|
}}
|
||||||
placeholder={{ blurhash: src?.blurhash }}
|
placeholder={{ blurhash: src?.blurhash }}
|
||||||
accessibilityLabel={alt}
|
accessibilityLabel={alt}
|
||||||
{...(css([layout, { overflow: "hidden" }], props) as any)}
|
{...(css(
|
||||||
|
[layout, { overflow: "hidden", backgroundColor: theme.overlay0 }],
|
||||||
|
props,
|
||||||
|
) as any)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,7 @@ export const Image = ({
|
|||||||
style?: ImageStyle;
|
style?: ImageStyle;
|
||||||
layout: ImageLayout;
|
layout: ImageLayout;
|
||||||
}) => {
|
}) => {
|
||||||
const { css } = useYoshiki();
|
const { css, theme } = useYoshiki();
|
||||||
const { apiUrl, authToken } = useToken();
|
const { apiUrl, authToken } = useToken();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -51,7 +51,10 @@ export const Image = ({
|
|||||||
}}
|
}}
|
||||||
placeholder={{ blurhash: src?.blurhash }}
|
placeholder={{ blurhash: src?.blurhash }}
|
||||||
accessibilityLabel={alt}
|
accessibilityLabel={alt}
|
||||||
{...(css([layout, { borderRadius: 6 }], props) as any)}
|
{...(css(
|
||||||
|
[layout, { borderRadius: 6, backgroundColor: theme.overlay0 }],
|
||||||
|
props,
|
||||||
|
) as any)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -108,7 +108,6 @@ export const Skeleton = ({
|
|||||||
colors={["transparent", theme.overlay1, "transparent"]}
|
colors={["transparent", theme.overlay1, "transparent"]}
|
||||||
style={[
|
style={[
|
||||||
StyleSheet.absoluteFillObject,
|
StyleSheet.absoluteFillObject,
|
||||||
{ transform: [{ translateX: -width.value }] },
|
|
||||||
animated,
|
animated,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
tooltip,
|
tooltip,
|
||||||
} from "~/primitives";
|
} from "~/primitives";
|
||||||
|
|
||||||
export const Back = ({ name, ...props }: { name: string } & ViewProps) => {
|
export const Back = ({ name, ...props }: { name?: string } & ViewProps) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -35,49 +35,19 @@ export const Back = ({ name, ...props }: { name: string } & ViewProps) => {
|
|||||||
onPress={router.back}
|
onPress={router.back}
|
||||||
{...tooltip(t("player.back"))}
|
{...tooltip(t("player.back"))}
|
||||||
/>
|
/>
|
||||||
<H1
|
{name ? (
|
||||||
{...css({
|
<H1
|
||||||
alignSelf: "center",
|
{...css({
|
||||||
fontSize: rem(1.5),
|
alignSelf: "center",
|
||||||
marginLeft: rem(1),
|
fontSize: rem(1.5),
|
||||||
})}
|
marginLeft: rem(1),
|
||||||
>
|
})}
|
||||||
{name}
|
>
|
||||||
</H1>
|
{name}
|
||||||
</View>
|
</H1>
|
||||||
);
|
) : (
|
||||||
};
|
<Skeleton {...css({ width: rem(5) })} />
|
||||||
|
|
||||||
Back.Loader = (props: ViewProps) => {
|
|
||||||
const { css } = useYoshiki();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
{...css(
|
|
||||||
{
|
|
||||||
position: "absolute",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bg: (theme) => theme.darkOverlay,
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
padding: percent(0.33),
|
|
||||||
color: "white",
|
|
||||||
},
|
|
||||||
props,
|
|
||||||
)}
|
)}
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
icon={ArrowBack}
|
|
||||||
as={PressableFeedback}
|
|
||||||
onPress={router.back}
|
|
||||||
{...tooltip(t("player.back"))}
|
|
||||||
/>
|
|
||||||
<Skeleton {...css({ width: rem(5) })} />
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,7 @@ import type { ComponentProps } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Platform, View, type ViewProps } from "react-native";
|
import { Platform, View, type ViewProps } from "react-native";
|
||||||
import type { VideoPlayer } from "react-native-video";
|
import type { VideoPlayer } from "react-native-video";
|
||||||
import { percent, useYoshiki } from "yoshiki/native";
|
import { percent, rem, useYoshiki } from "yoshiki/native";
|
||||||
import type { Chapter, KImage } from "~/models";
|
import type { Chapter, KImage } from "~/models";
|
||||||
import {
|
import {
|
||||||
H2,
|
H2,
|
||||||
@ -12,6 +12,7 @@ import {
|
|||||||
Link,
|
Link,
|
||||||
type Menu,
|
type Menu,
|
||||||
Poster,
|
Poster,
|
||||||
|
Skeleton,
|
||||||
tooltip,
|
tooltip,
|
||||||
ts,
|
ts,
|
||||||
useIsTouch,
|
useIsTouch,
|
||||||
@ -31,11 +32,11 @@ export const BottomControls = ({
|
|||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
player: VideoPlayer;
|
player: VideoPlayer;
|
||||||
poster: KImage;
|
poster?: KImage | null;
|
||||||
name: string;
|
name?: string;
|
||||||
chapters: Chapter[];
|
chapters: Chapter[];
|
||||||
previous: string | null;
|
previous?: string | null;
|
||||||
next: string | null;
|
next?: string | null;
|
||||||
setMenu: (isOpen: boolean) => void;
|
setMenu: (isOpen: boolean) => void;
|
||||||
} & ViewProps) => {
|
} & ViewProps) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
@ -57,25 +58,34 @@ export const BottomControls = ({
|
|||||||
position: "relative",
|
position: "relative",
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Poster
|
{poster !== undefined ? (
|
||||||
src={poster}
|
<Poster
|
||||||
quality="low"
|
src={poster}
|
||||||
layout={{ width: percent(100) }}
|
quality="low"
|
||||||
{...(css({ position: "absolute", bottom: 0 }) as any)}
|
layout={{ width: percent(100) }}
|
||||||
/>
|
{...(css({ position: "absolute", bottom: 0 }) as any)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Poster.Loader
|
||||||
|
layout={{ width: percent(100) }}
|
||||||
|
{...(css({ position: "absolute", bottom: 0 }) as any)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
<View
|
<View
|
||||||
{...css({
|
{...css({
|
||||||
marginLeft: { xs: ts(0.5), sm: ts(3) },
|
marginHorizontal: { xs: ts(0.5), sm: ts(3) },
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
flexGrow: 1,
|
flex: 1,
|
||||||
flexShrink: 1,
|
|
||||||
maxWidth: percent(100),
|
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<H2 numberOfLines={1} {...css({ paddingBottom: ts(1) })}>
|
{name ? (
|
||||||
name
|
<H2 numberOfLines={1} {...css({ paddingBottom: ts(1) })}>
|
||||||
</H2>
|
{name}
|
||||||
|
</H2>
|
||||||
|
) : (
|
||||||
|
<Skeleton {...css({ width: rem(15), height: rem(2) })} />
|
||||||
|
)}
|
||||||
<ProgressBar player={player} chapters={chapters} />
|
<ProgressBar player={player} chapters={chapters} />
|
||||||
<ControlButtons
|
<ControlButtons
|
||||||
player={player}
|
player={player}
|
||||||
@ -96,8 +106,8 @@ const ControlButtons = ({
|
|||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
player: VideoPlayer;
|
player: VideoPlayer;
|
||||||
previous: string | null;
|
previous?: string | null;
|
||||||
next: string | null;
|
next?: string | null;
|
||||||
setMenu: (isOpen: boolean) => void;
|
setMenu: (isOpen: boolean) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
@ -116,7 +126,7 @@ const ControlButtons = ({
|
|||||||
{...css(
|
{...css(
|
||||||
{
|
{
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
flexGrow: 1,
|
flex: 1,
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
flexWrap: "wrap",
|
flexWrap: "wrap",
|
||||||
},
|
},
|
||||||
@ -124,7 +134,7 @@ const ControlButtons = ({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<View {...css({ flexDirection: "row" })}>
|
<View {...css({ flexDirection: "row" })}>
|
||||||
{isTouch && (
|
{!isTouch && (
|
||||||
<View {...css({ flexDirection: "row" })}>
|
<View {...css({ flexDirection: "row" })}>
|
||||||
{previous && (
|
{previous && (
|
||||||
<IconButton
|
<IconButton
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import type { ViewProps } from "react-native";
|
import type { ViewProps } from "react-native";
|
||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import type { VideoPlayer } from "react-native-video";
|
import type { VideoPlayer } from "react-native-video";
|
||||||
import { useYoshiki } from "yoshiki/native";
|
import { useYoshiki } from "yoshiki/native";
|
||||||
import type { Chapter, KImage } from "~/models";
|
import type { Chapter, KImage } from "~/models";
|
||||||
@ -11,22 +13,23 @@ import { TouchControls } from "./touch";
|
|||||||
|
|
||||||
export const Controls = ({
|
export const Controls = ({
|
||||||
player,
|
player,
|
||||||
title,
|
name,
|
||||||
subTitle,
|
|
||||||
poster,
|
poster,
|
||||||
|
subName,
|
||||||
chapters,
|
chapters,
|
||||||
previous,
|
previous,
|
||||||
next,
|
next,
|
||||||
}: {
|
}: {
|
||||||
player: VideoPlayer;
|
player: VideoPlayer;
|
||||||
title: string;
|
name?: string;
|
||||||
subTitle: string;
|
poster?: KImage | null;
|
||||||
poster: KImage;
|
subName?: string;
|
||||||
chapters: Chapter[];
|
chapters: Chapter[];
|
||||||
previous: string | null;
|
previous?: string | null;
|
||||||
next: string | null;
|
next?: string | null;
|
||||||
}) => {
|
}) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
const isTouch = useIsTouch();
|
const isTouch = useIsTouch();
|
||||||
|
|
||||||
const [hover, setHover] = useState(false);
|
const [hover, setHover] = useState(false);
|
||||||
@ -44,9 +47,13 @@ export const Controls = ({
|
|||||||
} satisfies ViewProps;
|
} satisfies ViewProps;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchControls player={player} forceShow={hover || menuOpenned}>
|
<TouchControls
|
||||||
|
player={player}
|
||||||
|
forceShow={hover || menuOpenned}
|
||||||
|
{...css(StyleSheet.absoluteFillObject)}
|
||||||
|
>
|
||||||
<Back
|
<Back
|
||||||
name={title}
|
name={name}
|
||||||
{...css(
|
{...css(
|
||||||
{
|
{
|
||||||
// pointerEvents: "auto",
|
// pointerEvents: "auto",
|
||||||
@ -55,6 +62,9 @@ export const Controls = ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bg: (theme) => theme.darkOverlay,
|
bg: (theme) => theme.darkOverlay,
|
||||||
|
paddingTop: insets.top,
|
||||||
|
paddingLeft: insets.left,
|
||||||
|
paddingRight: insets.right,
|
||||||
},
|
},
|
||||||
hoverControls,
|
hoverControls,
|
||||||
)}
|
)}
|
||||||
@ -64,7 +74,7 @@ export const Controls = ({
|
|||||||
)}
|
)}
|
||||||
<BottomControls
|
<BottomControls
|
||||||
player={player}
|
player={player}
|
||||||
name={subTitle}
|
name={subName}
|
||||||
poster={poster}
|
poster={poster}
|
||||||
chapters={chapters}
|
chapters={chapters}
|
||||||
previous={previous}
|
previous={previous}
|
||||||
@ -79,6 +89,9 @@ export const Controls = ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bg: (theme) => theme.darkOverlay,
|
bg: (theme) => theme.darkOverlay,
|
||||||
|
paddingLeft: insets.left,
|
||||||
|
paddingRight: insets.right,
|
||||||
|
paddingBottom: insets.bottom,
|
||||||
},
|
},
|
||||||
hoverControls,
|
hoverControls,
|
||||||
)}
|
)}
|
||||||
|
@ -39,9 +39,9 @@ export const ProgressBar = ({
|
|||||||
}}
|
}}
|
||||||
setProgress={setSeek}
|
setProgress={setSeek}
|
||||||
endSeek={() => {
|
endSeek={() => {
|
||||||
setProgress(seek!);
|
player.seekTo(seek!);
|
||||||
setSeek(null);
|
|
||||||
setTimeout(player.play, 10);
|
setTimeout(player.play, 10);
|
||||||
|
setSeek(null);
|
||||||
}}
|
}}
|
||||||
// onHover={(progress, layout) => {
|
// onHover={(progress, layout) => {
|
||||||
// setHoverProgress(progress);
|
// setHoverProgress(progress);
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
Pressable,
|
Pressable,
|
||||||
type PressableProps,
|
type PressableProps,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import type { VideoPlayer } from "react-native-video";
|
import { useEvent, type VideoPlayer } from "react-native-video";
|
||||||
import { useYoshiki } from "yoshiki/native";
|
import { useYoshiki } from "yoshiki/native";
|
||||||
import { useIsTouch } from "~/primitives";
|
import { useIsTouch } from "~/primitives";
|
||||||
|
|
||||||
@ -18,9 +18,14 @@ export const TouchControls = ({
|
|||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
const isTouch = useIsTouch();
|
const isTouch = useIsTouch();
|
||||||
|
|
||||||
const [_show, setShow] = useState(true);
|
const [playing, setPlay] = useState(player.isPlaying);
|
||||||
|
useEvent(player, "onPlaybackStateChange", (status) => {
|
||||||
|
setPlay(status.isPlaying);
|
||||||
|
});
|
||||||
|
|
||||||
|
const [_show, setShow] = useState(false);
|
||||||
const hideTimeout = useRef<NodeJS.Timeout | null>(null);
|
const hideTimeout = useRef<NodeJS.Timeout | null>(null);
|
||||||
const shouldShow = forceShow || _show;
|
const shouldShow = forceShow || _show || !playing;
|
||||||
const show = useCallback((val: boolean = true) => {
|
const show = useCallback((val: boolean = true) => {
|
||||||
setShow(val);
|
setShow(val);
|
||||||
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
||||||
|
@ -10,31 +10,15 @@ import { type QueryIdentifier, useFetch } from "~/query";
|
|||||||
import { useQueryState } from "~/utils";
|
import { useQueryState } from "~/utils";
|
||||||
import { Controls, LoadingIndicator } from "./controls";
|
import { Controls, LoadingIndicator } from "./controls";
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
return {
|
|
||||||
currentEntry,
|
|
||||||
title: `${entry.name} (${entryDisplayNumber(entry)})`,
|
|
||||||
description: entry.description,
|
|
||||||
subtitle: item.show!.kind !== "movie" ? item.show!.name : null,
|
|
||||||
poster: item.show!.poster,
|
|
||||||
thumbnail: item.show!.thumbnail,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Player = () => {
|
export const Player = () => {
|
||||||
const [slug, setSlug] = useQueryState<string>("slug", undefined!);
|
const [slug, setSlug] = useQueryState<string>("slug", undefined!);
|
||||||
const [start, setStart] = useQueryState<number | undefined>("t", undefined);
|
const [start, setStart] = useQueryState<number | undefined>("t", undefined);
|
||||||
|
|
||||||
const { data, error } = useFetch(Player.query(slug));
|
const { data, error } = useFetch(Player.query(slug));
|
||||||
const { data: info, error: infoError } = useFetch(Player.infoQuery(slug));
|
const { data: info, error: infoError } = useFetch(Player.infoQuery(slug));
|
||||||
const metadata = mapMetadata(data);
|
// TODO: map current entry using entries' duration & the current playtime
|
||||||
|
const currentEntry = 0;
|
||||||
|
const entry = data?.entries[currentEntry] ?? data?.entries[0];
|
||||||
|
|
||||||
const { apiUrl, authToken } = useToken();
|
const { apiUrl, authToken } = useToken();
|
||||||
const [playMode] = useLocalSetting<"direct" | "hls">("playMode", "direct");
|
const [playMode] = useLocalSetting<"direct" | "hls">("playMode", "direct");
|
||||||
@ -44,15 +28,15 @@ export const Player = () => {
|
|||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${authToken}`,
|
Authorization: `Bearer ${authToken}`,
|
||||||
},
|
},
|
||||||
externalSubtitles: info?.subtitles
|
// externalSubtitles: info?.subtitles
|
||||||
.filter((x) => x.link)
|
// .filter((x) => x.link)
|
||||||
.map((x) => ({
|
// .map((x) => ({
|
||||||
uri: x.link!,
|
// uri: x.link!,
|
||||||
// TODO: translate this `Unknown`
|
// // TODO: translate this `Unknown`
|
||||||
label: x.title ?? "Unknown",
|
// label: x.title ?? "Unknown",
|
||||||
language: x.language ?? "und",
|
// language: x.language ?? "und",
|
||||||
type: x.codec,
|
// type: x.codec,
|
||||||
})),
|
// })),
|
||||||
},
|
},
|
||||||
(p) => {
|
(p) => {
|
||||||
p.playWhenInactive = true;
|
p.playWhenInactive = true;
|
||||||
@ -111,9 +95,9 @@ export const Player = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Head
|
<Head
|
||||||
title={metadata?.title}
|
title={entry ? `${entry.name} (${entryDisplayNumber(entry)})` : null}
|
||||||
description={metadata?.description}
|
description={entry?.description}
|
||||||
image={metadata?.thumbnail?.high}
|
image={data?.show?.thumbnail?.high}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
options={{
|
options={{
|
||||||
@ -129,15 +113,24 @@ export const Player = () => {
|
|||||||
pictureInPicture
|
pictureInPicture
|
||||||
autoEnterPictureInPicture
|
autoEnterPictureInPicture
|
||||||
resizeMode={"contain"}
|
resizeMode={"contain"}
|
||||||
controls
|
|
||||||
style={StyleSheet.absoluteFillObject}
|
style={StyleSheet.absoluteFillObject}
|
||||||
/>
|
/>
|
||||||
<ContrastArea mode="dark">
|
<ContrastArea mode="dark">
|
||||||
<LoadingIndicator player={player} />
|
<LoadingIndicator player={player} />
|
||||||
<Controls
|
<Controls
|
||||||
player={player}
|
player={player}
|
||||||
title={metadata?.title}
|
name={data?.show?.name}
|
||||||
subTitle={metadata?.subtitle}
|
poster={data?.show?.poster}
|
||||||
|
subName={
|
||||||
|
entry
|
||||||
|
? [entryDisplayNumber(entry), entry.name]
|
||||||
|
.filter((x) => x)
|
||||||
|
.join(" - ")
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
chapters={info?.chapters ?? []}
|
||||||
|
previous={data?.previous?.video}
|
||||||
|
next={data?.next?.video}
|
||||||
/>
|
/>
|
||||||
</ContrastArea>
|
</ContrastArea>
|
||||||
</View>
|
</View>
|
||||||
@ -147,7 +140,7 @@ export const Player = () => {
|
|||||||
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", "show"],
|
with: ["next", "previous", "show"],
|
||||||
},
|
},
|
||||||
parser: FullVideo,
|
parser: FullVideo,
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user