From 399fb3fe3830d1f9c0564d384034dc918398fae8 Mon Sep 17 00:00:00 2001 From: Sawa <34698182+sawaYch@users.noreply.github.com> Date: Fri, 29 Mar 2024 20:27:08 +0800 Subject: [PATCH] feat(docs): update README.md --- README.md | 167 +++++++++++++++++++- apps/web/package.json | 10 +- package-lock.json | 3 +- packages/next-youtube-livechat/README.md | 15 +- packages/next-youtube-livechat/package.json | 2 +- 5 files changed, 182 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 7163b2e..db8198e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,166 @@ # Next Youtube Livechat Monorepo This is the monorepo for next-youtube-livechat package hook, create with [Turborepo](https://turbo.build/repo). -Contains a demo NextJS 14 website demonstrate the usage of `next-youtube-livechat` react hook library. +Include a demo NextJS 14 website demonstrate the usage of `next-youtube-livechat` react hook library. + +## Package `next-youtube-livechat` + +Fetch YouTube live chat without API using NextJS which bypass CORS. +Demo site: [https://next-youtube-livechat.vercel.app/](https://next-youtube-livechat.vercel.app/) + +🚨 You will need to take full responsibility for your action 🚨 + +### Getting started + +#### Installation + +> Package already provide types files + +```ts +npm i next-youtube-livechat +``` + +#### Source Code + +Hook + +> React hook for getting livestream message data, event handling + +- `src/hooks/useLiveChat.tsx` + +Youtube related functions + +> Use to parse chat message / emoji +> API functions contain payload for fetching live chatroom (without using YouTube Data API) + +- `src/lib/yt-api-parser.ts` +- `src/lib/yt-api-requests.ts` + +#### Usage + +##### NextJS API + +Add the follow API code to bypass CORS, otherwise this library will not work. +Here is the example for NextJS 14 app directory: + +`app\api\yt-api\[...slug]\route.ts` + +```ts +import { NextRequest, NextResponse } from 'next/server'; + +const YOUTUBE_URL = 'https://www.youtube.com'; + +const buildYouTubeEndpoint = (req: NextRequest) => { + const path = req.nextUrl.pathname.replace('/api/yt-api', ''); + const suffix = `${path}${req.nextUrl.search}`; + const url = `${YOUTUBE_URL}${suffix}`; + return url; +}; + +const GET = async (req: NextRequest) => { + const res = await fetch(buildYouTubeEndpoint(req), { cache: 'no-store' }) + .then((d) => d.text()) + .then((d) => { + return d; + }) + .catch((error) => { + throw new Error(`Server Action Failed: ${error.message}`); + }); + return NextResponse.json(res, { status: 200 }); +}; + +const POST = async (req: NextRequest) => { + const postData = await req.json(); + const data = await fetch(buildYouTubeEndpoint(req), { + method: 'POST', + cache: 'no-store', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(postData), + }) + .then((d) => d.json()) + .catch((error) => { + throw new Error(`Server Action Failed: ${error.message}`); + }); + return NextResponse.json(data, { status: 200 }); +}; + +export { GET, POST }; +``` + +##### Example + +```ts +import { useLiveChat } from 'next-youtube-livechat'; + +/** Example Demo page component **/ +export const Demo = () => { + /** loading state, optional. Can use to control show spinner before fetching start & hide spinner after fetching start **/ + const [isLoading, setIsLoading] = useState(); + + /** ready state, required. Use to control start/termination of chat message polling **/ + const [isReady, setIsReady] = useState(); + + /** url state, required. Use to provide YouTube livestream target to fetch chat message **/ + const [url, setUrl] = useState(); + + const onBeforeStart = useCallback(async () => { + setIsLoading(true); + }, [setIsLoading]); + + const onStart = useCallback(async () => { + setIsLoading(false); + setIsReady(true); + }, [setIsLoading, setIsReady]); + + const onChatItemsReceive = useCallback(async (newChatItems: ChatItem[], existingChatItems: ChatItem[]) => { + console.log('new chat items', newChatItems); + console.log('received chat items', existingChatItems); + }, []); + + const onError = useCallback(async () => { + setIsLoading(false); + setIsReady(false); + setUrl(); + }, [setIsLoading, setIsReady, setUrl]); + + const { displayedMessage, rawChatItems, liveDetails } = useLiveChat({ + url, + isReady, + onBeforeStart, + onStart, + onChatItemsReceive, + onError, + }); + +return (
+ {liveDetails && ( +
+ thumbnail +
{liveDetails.title}
+
Channel Owner Name: {liveDetails.channelName}
+
Channel Profile URL: {liveDetails.channelUrl}
+
+ )} + {displayedMessage?.map((it, index) => ( + {it.message} + ))} +
) +} +``` + +### Reference + +Part of the code is referenced from [LinaTsukusu/youtube-chat](https://github.com/LinaTsukusu/youtube-chat), many thanks 🙌 + + + ## Monorepo structure @@ -24,7 +183,7 @@ Contains a demo NextJS 14 website demonstrate the usage of `next-youtube-livecha └── turbo.json ``` -- `apps/web` - Demo website +- `apps/web` - Demo website - `packages/next-youtube-livechat` - React hook library `next-youtube-livechat` - `packages/eslint-config` - eslint configurations (includes `eslint-config-next`, `eslint-config-prettier` and `eslint-config-turbo`) - `packages/typescript-config` - tsconfig.json used throughout the monorepo @@ -38,8 +197,8 @@ Restore dependencies: npm i ``` -To develop all apps and packages, run: -Both app & packages should be hot reload on file changed, and supporting linting & typecheck. +Developing apps & packages should be able to hot reload on file changed, also with linting & typecheck. +To develop (all apps and packages), run: ```sh turbo dev diff --git a/apps/web/package.json b/apps/web/package.json index a5b943a..905700d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -12,10 +12,6 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "next": "^14.1.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "next-youtube-livechat": "*", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-slot": "^1.0.2", @@ -25,8 +21,12 @@ "clsx": "^2.1.0", "framer-motion": "^11.0.20", "lucide-react": "^0.338.0", + "next": "^14.1.1", "next-themes": "^0.2.1", + "next-youtube-livechat": "*", + "react": "^18.2.0", "react-device-detect": "^2.2.3", + "react-dom": "^18.2.0", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", "zustand": "^4.5.2" @@ -35,8 +35,8 @@ "@next/eslint-plugin-next": "^14.1.1", "@repo/eslint-config": "*", "@repo/typescript-config": "*", - "@types/eslint": "^8.56.5", "@trivago/prettier-plugin-sort-imports": "^4.3.0", + "@types/eslint": "^8.56.5", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", diff --git a/package-lock.json b/package-lock.json index 4c0b34f..c0b13b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8967,7 +8967,8 @@ } }, "packages/next-youtube-livechat": { - "version": "0.1.16", + "version": "0.1.22", + "license": "MIT", "dependencies": { "next": "^14.1.1", "react": "^18", diff --git a/packages/next-youtube-livechat/README.md b/packages/next-youtube-livechat/README.md index 6cec8b9..bb59891 100644 --- a/packages/next-youtube-livechat/README.md +++ b/packages/next-youtube-livechat/README.md @@ -1,13 +1,20 @@ # `next-youtube-livechat` -Fetch YouTube live chat without API using NextJS which bypass CORS. - -🚨 You will need to take full responsibility for your action 🚨 - +Fetch YouTube live chat without API using NextJS which bypass CORS. Demo site: [https://next-youtube-livechat.vercel.app/](https://next-youtube-livechat.vercel.app/) +🚨 You will need to take full responsibility for your action 🚨 + ## Getting started +### Installation + +> Package already provide types files + +```ts +npm i next-youtube-livechat +``` + ### Source Code Hook diff --git a/packages/next-youtube-livechat/package.json b/packages/next-youtube-livechat/package.json index b8b22d4..d0a35ad 100644 --- a/packages/next-youtube-livechat/package.json +++ b/packages/next-youtube-livechat/package.json @@ -1,6 +1,6 @@ { "name": "next-youtube-livechat", - "version": "0.1.22", + "version": "0.1.23", "private": false, "description": "Fetch YouTube live chat without API using NextJS + React Hook which bypass CORS.", "author": "Sawa",