From 0422fb4875d79dbfaeea1608047513c806a5bcd7 Mon Sep 17 00:00:00 2001 From: Artemy Date: Wed, 9 Aug 2023 21:38:13 +0300 Subject: [PATCH] feat: channel --- index.html | 2 +- package-lock.json | 8 +-- package.json | 2 +- src/App.tsx | 8 ++- src/components/utils.ts | 4 ++ src/components/video.tsx | 19 +++++- src/pages/channel.tsx | 129 +++++++++++++++++++++++++++++++++++++++ src/pages/trending.tsx | 4 +- tsconfig.json | 4 +- 9 files changed, 166 insertions(+), 14 deletions(-) create mode 100644 src/pages/channel.tsx diff --git a/index.html b/index.html index 53b3037..d81957c 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ - Vite + React + TS + ULTYT diff --git a/package-lock.json b/package-lock.json index 1f92b65..9f4d41b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "@heroicons/react": "^2.0.18", "@nextui-org/react": "^2.0.7", "framer-motion": "^10.15.1", - "piped-api": "^1.1.6", + "piped-api": "^1.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.14.2" @@ -4439,9 +4439,9 @@ } }, "node_modules/piped-api": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/piped-api/-/piped-api-1.1.6.tgz", - "integrity": "sha512-Tyn6/x/nBass469Io5zyILKylQI6sHE0MIYPYgD5nD232TmBF3G0OU+AQrvqU6cCla+Bkff3oFo+4GhnJKeiuA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/piped-api/-/piped-api-1.2.0.tgz", + "integrity": "sha512-180w5tI7/I4bPQ0+Jwl5fj84cd+bffq4XihK9lt6zbUQdmbIcxVsJ/zi83rUAJGAijCp0/BuZeGywpKp9Lt5NA==", "dependencies": { "axios": "^1.4.0" } diff --git a/package.json b/package.json index 8c2f628..1b54131 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@heroicons/react": "^2.0.18", "@nextui-org/react": "^2.0.7", "framer-motion": "^10.15.1", - "piped-api": "^1.1.6", + "piped-api": "^1.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.14.2" diff --git a/src/App.tsx b/src/App.tsx index 96ff626..283e157 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,8 +3,9 @@ import "./App.css"; import { NextUIProvider } from "@nextui-org/react"; import { PipedAPI } from "piped-api"; import { HashRouter, Navigate, Route, Routes } from "react-router-dom"; -import Trending from "./pages/trending"; +import TrendingPage from "./pages/trending"; import { NavbarComponent } from "./components/navbar"; +import ChannelPage from "./pages/channel"; declare global { interface Window { @@ -12,7 +13,7 @@ declare global { } } function App() { - window.piped_api = new PipedAPI(); //"https://ytapi.dc09.ru"); + window.piped_api = new PipedAPI("https://ytapi.dc09.ru"); return ( @@ -20,7 +21,8 @@ function App() { } /> - } /> + } /> + } /> diff --git a/src/components/utils.ts b/src/components/utils.ts index f68727a..6f52323 100644 --- a/src/components/utils.ts +++ b/src/components/utils.ts @@ -6,3 +6,7 @@ export function shortenNumber(number: number) { } return number.toString(); } + +export function capitalize(string: string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} diff --git a/src/components/video.tsx b/src/components/video.tsx index ff17eba..7d4b4c9 100644 --- a/src/components/video.tsx +++ b/src/components/video.tsx @@ -10,7 +10,7 @@ import { Video } from "piped-api/dist/types"; import { useNavigate } from "react-router-dom"; import { CheckCircleIcon, EyeIcon } from "@heroicons/react/24/solid"; import { shortenNumber } from "./utils"; -export function VideoComponent({ video }: VideoComponentProps) { +export function VideoComponent({ video, uploaderAvatar }: VideoComponentProps) { const navigate = useNavigate(); return ( @@ -24,7 +24,10 @@ export function VideoComponent({ video }: VideoComponentProps) { - +
{video.title} @@ -61,7 +64,19 @@ export function SkeletonVideoComponent() { ); } +export function VideoContainer({ children }: VideoContainerProps) { + return ( +
+ {children} +
+ ); +} type VideoComponentProps = { video: Video; + uploaderAvatar?: string; +}; + +type VideoContainerProps = { + children: React.ReactNode; }; diff --git a/src/pages/channel.tsx b/src/pages/channel.tsx new file mode 100644 index 0000000..31a1f5c --- /dev/null +++ b/src/pages/channel.tsx @@ -0,0 +1,129 @@ +import { Channel, Tab, Video } from "piped-api/dist/types"; +import { useEffect, useState } from "react"; +import { + SkeletonVideoComponent, + VideoComponent, + VideoContainer, +} from "../components/video"; +import { useParams, useSearchParams } from "react-router-dom"; +import { Card, CardFooter } from "@nextui-org/react"; +import { capitalize } from "../components/utils"; + +export default function ChannelPage() { + const [channel, setChannel] = useState(); + const [tab, setTab] = useState(); + + const { id } = useParams(); + const [searchParams, setSearchParams] = useSearchParams(); + const tabId = searchParams.get("tabId") || "videos"; + + useEffect(() => { + async function getChannel() { + const channel = (await window.piped_api.channel(id || "")) as Channel; + setChannel(channel); + } + + async function getTab(name: string) { + const tab = await window.piped_api.channelTabs(channel?.tabs[name].data); + setTab(tab); + } + + if (!channel) { + getChannel(); + } + + if (!tab && tabId !== "videos") { + getTab(tabId); + } + }); + + if (!channel) { + return ( +
+ {[...Array(20).keys()].map((num) => ( + + ))} +
+ ); + } else { + return ( +
+
+ +
+ +
+ +
+
+ {channel.name} +
+
+
+
+
+ +
+
{ + setSearchParams({ tabId: "videos" }); + }} + key="videos" + className="text-xl font-bold p-4" + > + Videos +
+ {channel.tabs.map((tab, index) => { + return ( +
{ + setSearchParams({ tabId: String(index) }); + setTab(undefined); + }} + key={tab.name} + className="text-xl font-bold p-4" + > + {capitalize(tab.name)} +
+ ); + })} +
+ + {tabId !== "videos" ? ( + + {tab?.content.map((video) => { + if (video.type === "stream") { + video = video as Video; + return ( + + ); + } else { + return ( +
+ Soon... +
+ ); + } + })} +
+ ) : ( + + {channel.relatedStreams.map((video) => ( + + ))} + + )} +
+ ); + } +} diff --git a/src/pages/trending.tsx b/src/pages/trending.tsx index 2e00043..c1aba1b 100644 --- a/src/pages/trending.tsx +++ b/src/pages/trending.tsx @@ -2,12 +2,12 @@ import { Video } from "piped-api/dist/types"; import { useEffect, useState } from "react"; import { SkeletonVideoComponent, VideoComponent } from "../components/video"; -export default function Trending() { +export default function TrendingPage() { const [trending, setTrending] = useState([] as Video[]); useEffect(() => { async function getTrending() { - const trending = await window.piped_api.trending("US"); //await window.piped_api.search("artegoser"); + const trending = await window.piped_api.trending("US"); setTrending(trending); } diff --git a/tsconfig.json b/tsconfig.json index a7fc6fb..d03a6ad 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,7 +18,9 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + + "noImplicitAny": false }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }]