You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
3.5 KiB
165 lines
3.5 KiB
import NotFound from "./404";
|
|
|
|
import { GetStaticProps, NextPage } from "next";
|
|
import { NextSeo } from "next-seo";
|
|
import Link from "next/link";
|
|
import { useRouter } from "next/router";
|
|
|
|
import { useQuery } from "react-query";
|
|
|
|
import axios, { AxiosError } from "axios";
|
|
|
|
import Avatar from "@mui/material/Avatar";
|
|
import Box from "@mui/material/Box";
|
|
import Container from "@mui/material/Container";
|
|
import Divider from "@mui/material/Divider";
|
|
import Typography from "@mui/material/Typography";
|
|
import { useTheme } from "@mui/material/styles";
|
|
|
|
import Share from "@mui/icons-material/Share";
|
|
|
|
import { abbreviateNumber } from "@src/utils";
|
|
|
|
import { Error } from "@interfaces/api";
|
|
import VideoAPI from "@interfaces/api/video";
|
|
|
|
import useSettings from "@utils/hooks/useSettings";
|
|
|
|
import Layout from "@components/Layout";
|
|
import Loading from "@components/Loading";
|
|
import Player from "@components/Player";
|
|
|
|
import styles from "./watch.module.css";
|
|
|
|
const Watch: NextPage = () => {
|
|
const { query, isReady } = useRouter();
|
|
|
|
const theme = useTheme();
|
|
|
|
const videoId = query["v"];
|
|
|
|
const [settings] = useSettings();
|
|
|
|
const { isLoading, error, data } = useQuery<
|
|
VideoAPI | null,
|
|
AxiosError<Error>
|
|
>(["videoData", videoId], () =>
|
|
videoId
|
|
? axios
|
|
.get(`https://${settings.invidiousServer}/api/v1/videos/${videoId}`, {
|
|
params: {}
|
|
})
|
|
.then((res) => res.data)
|
|
: null
|
|
);
|
|
|
|
if (!isReady || isLoading) {
|
|
return (
|
|
<>
|
|
<NextSeo title="Loading video..." />
|
|
<Layout>
|
|
<Loading />
|
|
</Layout>
|
|
</>
|
|
);
|
|
}
|
|
|
|
if (!videoId) {
|
|
return <NotFound />;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<NextSeo title={data ? data.title : "Not Found"} />
|
|
<Layout>
|
|
{data && (
|
|
<>
|
|
<Player
|
|
streams={data.formatStreams}
|
|
formats={data.adaptiveFormats}
|
|
captions={data.captions}
|
|
length={data.lengthSeconds}
|
|
videoId={data.videoId}
|
|
sx={{
|
|
height: "75vh",
|
|
margin: "auto",
|
|
mt: 2
|
|
}}
|
|
/>
|
|
<Container sx={{ mt: 2 }}>
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
alignItems: "center"
|
|
}}
|
|
>
|
|
<Box
|
|
sx={{
|
|
flex: 1
|
|
}}
|
|
>
|
|
<Typography variant="h4">{data.title}</Typography>
|
|
<Typography
|
|
variant="subtitle1"
|
|
color={theme.palette.text.secondary}
|
|
sx={{
|
|
mt: 1
|
|
}}
|
|
>
|
|
{abbreviateNumber(data.viewCount)} Views •{" "}
|
|
{new Date(data.published * 1000).toLocaleDateString()}
|
|
</Typography>
|
|
</Box>
|
|
<Share />
|
|
</Box>
|
|
|
|
<Divider sx={{ my: 2 }} />
|
|
|
|
<Link
|
|
href={{
|
|
pathname: `/channel`,
|
|
query: {
|
|
c: data.authorId
|
|
}
|
|
}}
|
|
>
|
|
<a>
|
|
<Box
|
|
sx={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
mb: 2
|
|
}}
|
|
>
|
|
<Avatar
|
|
src={
|
|
data?.authorThumbnails.find(
|
|
(thumbnail) => thumbnail.width == 100
|
|
)?.url
|
|
}
|
|
alt={data.author}
|
|
sx={{
|
|
mr: 2
|
|
}}
|
|
/>
|
|
<Typography variant="h6">{data.author}</Typography>
|
|
</Box>
|
|
</a>
|
|
</Link>
|
|
|
|
<Typography
|
|
className={styles.description}
|
|
dangerouslySetInnerHTML={{
|
|
__html: data.descriptionHtml.replaceAll("\n", "<br>")
|
|
}}
|
|
></Typography>
|
|
</Container>
|
|
</>
|
|
)}
|
|
</Layout>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Watch;
|