An open API service indexing awesome lists of open source software.

https://github.com/sougata-github/next-play

A modern video-sharing platform built using Next.js.
https://github.com/sougata-github/next-play

Last synced: 6 months ago
JSON representation

A modern video-sharing platform built using Next.js.

Awesome Lists containing this project

README

          

## Create a tRPC client for Client Components

The trpc/client.tsx is the entrypoint when consuming your tRPC API from client components. In here, import the type definition of your tRPC router and create typesafe hooks using createTRPCReact.

## Create a tRPC caller for Server Components

To prefetch queries from server components, we use a tRPC caller. The `@trpc/react-query/rsc` module exports a thin wrapper around `createCaller` that integrates with your React Query client.

## Hybrid data fetching pattern using both RSC & Client Components

Here we leverage the speed of `server component` to prefetch data and let the `client component` not have to fetch anything initially. It will have the data ready

Server Component (prefetching data)

```typescript
import { ErrorBoundary } from "react-error-boundary";
import { HydrateClient, trpc } from "@/trpc/server";
import { Suspense } from "react";

import { PageClient } from "./client";

export default async function Home() {
void trpc.hello.prefetch({ text: "Next.js" });

return (

Loading...}>
Error...}>




);
}
```

Client Component (with ready prefetched data)

```typescript
"use client";

import { trpc } from "@/trpc/client";

export const PageClient = () => {
const [data] = trpc.hello.useSuspenseQuery({
text: "Next.js",
});

return

{data.greeting}
;
};
```

So in this approach, the data is fetched once on the server and hydrated into the Client Component.

- Fetch and serialize data on the server.

- Send the serialized data to the client.

- On the client → `` deserializes and restores the data into React Query's cache.

Hydrating the data means restoring `pre-fetched` or `serialized data` back into its original format on the client-side so it can be used efficiently.

- Serialization is the process of converting complex data structures (like objects, arrays, dates, or custom classes) into a format that can be easily stored, transferred, or processed—typically into a string (JSON, binary, etc.).

- Since we are prefetching data in page.tsx, Next.js will consider it static, so we must declare `export const dynamic = "force-dynamic"`.

- Hydrate Client in the same component/page where you are prefetching data.

- When using `prefetchInfinite` in page.tsx, use `useSuspenseInfiniteQuery` in corresponding client component.

Advantages:

- trpc.hello.prefetch() ensures that the query result is cached and hydrated into the Client Component.

- When the Client Component mounts and calls `useSuspenseQuery`, it instantly gets the preloaded data from the cache instead of making another request.

- No unnecessary loading state in the Client Component (which would be the case if we use useQuery and isLoading in Client Component)

## tRPC Configuration

- Enable transformer on tRPC✅
- Add auth to tRPC context✅
- Add protectedProcedure✅
- Add rate limiting (using upstash)✅

## Video Categories

- Create categories schema✅
- Push changes to db✅
- Seed categories✅
- Organise tRPC routers✅
- Prefetch categories✅
- Create categories component✅

## Stuido layout

- Create studio route group✅
- Create studio layout✅
- Protect studio routes✅

## Studio Videos

- Create videos schema✅
- Push db changes✅
- Create studio procedures✅
- Add video record creation✅

## Infinite Loading

- Add Suspense and error boundaries✅
- Create reusable InfiniteScroll component✅
- Demonstrate infinite scroll✅

## Mux Integration

- Create Responsive Dialog✅
- Create a free Mux account✅
- Get a 15-second video✅
- Create upload modal✅

When we upload a video, it takes time to process, hence webhooks and since webhooks are anonymous, we need a way to preserve which user has uploaded, hence `userId` (metadata) to `passthrough`.

When we create a video, we also generate an upload url using Mux. We send this back to the Uploader and use it as an endpoint. After we upload the video, the webhook with `video.asset.created` is triggered and we update the video with the `upload url` (muxUploadId) record in our db with the status and asset id received from mux payload.

## Mux Webhooks

- Update video schema✅
- Push db changes✅
- Handle `video.asset.ready` event✅
- assign thumbnail
- assign preview
- Handle `video.asset.errored` event✅
- update status
- Handle `video.asset.deleted` event✅
- delete from db
- Handle `video.asset.track.ready` event✅
- update trackId and trackStatus

## Video Form

- Add Skeleton to videos-section✅
- Create video form page✅
- Create video player✅
- Add ability to update video information✅
- Title, Description, Category, Visibility✅

## Video Thumbnails

- Integrate UploadThing✅
- Add thumbnail upload functionality✅
- Add thumbnail restore functionality✅
- Refactor thumbnail fields in the schema✅
- Proper UploadThing cleanup✅

Unified approach to uploading files. Every file should be on `uploadthing`.

when creating/restoring a video:

get mux asset url (temp thumbnail) -> upload to uploadthing using utapi -> get url from uploadthing -> update db.

optimisation for future: load the entire form element until video is ready. use video.preparing for that. Show an overlay on top of the form.

## AI background jobs

Why background jobs?

- Avoid timeout from long-running tasks
- problematic with AI integrations
- Ensure retries in case of failure

- Integrate Upstash workflow✅
- Trigger a background job✅
- Add AI using vercel SDK✅
- Add background jobs✅

- Generate title✅
- Generate description✅
- Generate thumbnail✅

## AI Thumbnails

- Create thumbnail prompt modal✅
- Create thumbail generation workflow✅
- Add Skeleton to form-section loading state✅

## Video Page

- Create video "getOne" procedure✅
- inner-join "user" (author information)
- Prefetching process✅
- Video section✅
- Comments section (Placeholder)✅
- Suggestions section (Placeholder)✅

## Video Views

- Create video views schema✅
- Combine video views for "getOne" videos procedure✅
- Create video views creation procedure✅
- Trigger video view creation on video play✅

## Video reactions

- Create video reactions schema✅
- Combine video reactions for "getOne" videos procedure✅
- Create video reactions like & dislike procedure✅
- Connect VideoReactions component with new API✅

## Subscriptions

- Create subscriptions schema✅
- Combine subscriptions for "getOne" videos procedure✅
- Create subscriptions procedures✅
- Create SubscriptionButton component with new API✅

## Comments

- Create comments schema✅
- Create comments procedures✅
- Create comments section✅

## Comments Infinite Loading

- Modify comments "getMany" procedure✅
- Change prefect() to prefecthInfinte()✅
- Change suspense() to useSuspenseInfiniteQuery()✅
- Add InfiniteLoading component✅

## Comment Reactions

- Add "commentReactions" schema✅
- Create comment reactions UI✅
- Combine "commentReactions" with comments "getMany" procedure✅

## Comment Replies

- Extend comment schema by adding "parentId" foreign key✅
- Create UI for replies✅
- Modify comments "getMany" procedure by combining parentId✅
- Create variants for "CommentItem" component✅
- Create variants for "CommentForm" component✅
- Create CommentReplies component✅

## Suggestions

- Create suggestions procedure✅
- Prefetch suggestions✅
- Create VideoRowCard and VideoGrid components✅
- Connect Suggestions section with new API✅

## Search Page

- Add manual video re-validation✅
- in case webhook fail
- in case webhooks fire out of order
- Add proper categoryId query to suggestions✅
- Create search procedure✅
- Prefetch search page✅
- Connect search section to API✅

## Home Feed

- Create videos procedures✅
- Add Home page✅
- Add Trending page✅
- Add Subscriptions page✅

## Playlists

- Create playlists procedures✅
- Create History & Liked videos page✅

## Custom Playlists

- Create custom playlists schema✅
- Create custom playlists procedures✅
- Create playlists page✅

## Populate Playlists

- Create PlaylistAddModal component✅
- Create "getManyForVideo" playlist procedure✅
- Create add and remove procedures for playlists✅

## Individual Playlists

- Create "getVideos" procedure to load custom playlist's videos✅
- Build custom playlist page✅
- Add ability to delete a playlist✅
- Add ability to remove a video from a playlist✅

## User Page

- Add "bannerUrl" and "bannerKey" to user schema✅
- Create "users.getOne" procedure✅
- Modify "videos.getMany" procedure to accept userId prop✅
- Create userId page✅

## Banner Upload

- Implement "bannerUploader" endpoint in uploadthing/core.ts✅
- Create BannerUploadModal✅

## Subscriptions List

- Create subscriptions "getMany" procedure✅
- Load recent subscriptions in sidebar✅
- Create all subscriptions page✅