์ด๋ฒ ํ๋ก์ ํธ์์๋ video streaming ์ฌ์ดํธ ๊ฐ๋ฐ์ ํ๊ธฐ๋ก ํด๋ณธ๋ค. ๋จ์ํ๊ฒ video๋ฅผ ์ ๋ก๋ํ๊ณ ์๋ฒ์์ ์คํธ๋ฆฌ๋ฐ ํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํจ์ผ๋ก video ํ๋ซํผ์ ์๋ฆฌ๋ฅผ ์ดํดํ๋ ๊ฒ์ ๋ชฉํ๋ก ํ์๋ค. ํด๋ผ์ด์ธํธ๋ React ํ๋ ์์ํฌ์ธ Next.js๋ฅผ ์ฌ์ฉํ์๋ค.
์ฒ์์๋ ์ฌ์ฉ์๊ฐ ์ ์กํ video ํ์ผ์ ์๋ฒ์์ Buffer๋ก ๋ฐ์ DB๋ก ์ ์ฅํ๋ ค๊ณ ํ์๋ค. ํ์ง๋ง ๋ค์์ ์ฌ์ฉ์๊ฐ ์์์ ๋์์ ์ฌ๋ ค๋ ค ํ๋ค๋ฉด ์คํธ๋ฆฌ๋ฐ๋ ํด์ผํ๋ ์๋ฒ์ ๋ถ๋ด์ด ๋ ์๋ ์๋ค. ๋๋ฌธ์ ์๋ฒ๋ ์คํธ๋ฆฌ๋ฐํ๋ ์ญํ ๋ง ๋ด๋นํ๊ณ ์ ๋ก๋๋ ํด๋ผ์ด์ธํธ์์ ๋ด๋นํ๊ฒ ํ์ฌ ์ญํ ์ ๋ถ๋ฆฌํ์๋ค.
- Upload flow
yarn create next-app --typescript
yarn add mongodb axios busboy @types/busboy -D
- setFile to useState
const setFileHandler: React.ChangeEventHandler<HTMLInputElement> = (event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files;
if (files?.length) {
setFile(files[0]);
}
}
- submit to
/api/videos
page
const submitHandler: React.MouseEventHandler<HTMLButtonElement> = async () => {
const data = new FormData;
if (!file) return;
setSubmitting(true);
data.append('file', file);
// upload percentage
// progressEvent info (https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent)
const config: AxiosRequestConfig = {
onUploadProgress: function (progressEvent) {
let percentage = Math.round((progressEvent.loaded * 100) / progressEvent.total);
setProcess(percentage);
}
};
try {
await axios.post('/api/videos', data, config);
console.log(`video upload is Done.`);
} catch (error: any) {
setError(error.message);
} finally {
setSubmitting(false);
setProcess(0);
}
}
- upload Video to DB
what is GridFS ??
async function uploadVideoStream(
req: NextApiRequest,
res: NextApiResponse
) {
const bb = busboy({ headers: req.headers });
const client: MongoClient = new MongoClient(dbUri);
await client.connect();
const db: Db = client.db('videos');
const bucket = new GridFSBucket(db);
bb.on('file', (name, file, info) => {
const { filename, encoding, mimeType } = info;
console.log(`File[${name}]: filename: ${filename}, encoding: ${encoding}, mimeType: ${mimeType}`);
const videoUploadStream = bucket.openUploadStream(filename, {
chunkSizeBytes: 3145728,
metadata: { field: "free", value: "vlog" }
});
file.pipe(videoUploadStream);
});
bb.on('close', () => {
console.log('Done parsing video!');
res.writeHead(200, { 'Connection': 'close' });
res.end(`That's all folks`);
});
req.pipe(bb);
return;
}
DB์ ์ ์ฅ๋ ๋น๋์ค ๋ชฉ๋ก์ ๊ฐ์ ธ์ ํ๋ฉด์ ํ์
Next.js๋ฅผ ์ฌ์ฉํ๋ฉด ๋์ผํ ํ์ผ์์ getStaticProps๋ผ๋ ๋น๋๊ธฐ ํจ์๋ฅผ ๋ด๋ณด๋ผ ์ ์๋ค. ์ด ํจ์๋ ๋น๋ ์ ํธ์ถ๋๋ฉฐ, ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ ๋ ๋๋ง ์ ํ์ด์ง์ ์์ฑ์ผ๋ก ์ ๋ฌํ ์ ์๋ค.
๋น๋์ค ๋ชฉ๋ก์ ๊ฒฝ์ฐ ๋ฐ๋ก๋ฐ๋ก ๊ฐฑ์ ๋์ด์ผ ํ๋ฉฐ ์ด๋ฅผ CDN์์ DOM์ ๊ด๋ฆฌํ๊ฒ ๋๋ค. Static Generation์ page์์ ์ฌ์ฉํ๋ฉด ๋น๋ ํ์์ HTML์ด ์์ฑ๋๋ค. ์ด๊ธฐ HTML ์์ฑ ํ ๊ฐ ์์ฒญ์ด ์ฌ๋ ๋ง๋ค HTML์ด ์ฌ์ฌ์ฉ ๋๋ค.
๋์ ๊ฒฝ๋ก์ ๋ํ ํด๋ผ์ด์ธํธ ์ธก ํ์์ next/link
๋ก ์ฒ๋ฆฌ๋๋ค. ์๋์ PostLIst
์์ GetStaticProps
์ ๊ฒฐ๊ณผ๋ก ์์ฑ๋ posts์ filename์ ๊ฒฐ๊ณผ๋ฅผ link๋ก ํ์ํ๊ฒ ๋๋ค.
- PostList page
const PostList = ({ posts }: { posts: Post[] }) => {
return (
<div>
{posts.map((post, index) => (
<Link key={index} href="/videos/[id]" as={`/videos/${post.filename}`}>
<a><p>watch {post.filename}</p></a>
</Link>
))}
</div>
)
}
export const getStaticProps: GetStaticProps = async () => {
// Call an external API endpoint to get posts
const res = await fetch('http://localhost:5000/api/videos/posts')
const posts = await res.json()
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
๋์ ๊ฒฝ๋ก์ ๊ฒฐ๊ณผ๋ก ๋ณด์ฌ์ง๋ VideoPlayer page
import VideoPlayer from "../../components/VideoPlayer";
import { GetServerSideProps } from 'next'
import { useRouter } from "next/router";
export default function VideoPage() {
const router = useRouter();
const { id } = router.query as { id: string };
return (
<div>
<VideoPlayer id={id} />
</div>
)
}
export const getServerSideProps: GetServerSideProps = async (context) => {
return {
props: {
query: context.query
},
}
}
export default function VideoPlayer({ id }: { id: string }) {
return (
<div>
<video src={`http://localhost:5000/api/videos/file?videoId=${id}`}
controls
preload="metadata"
width="480px"
id="video-player"
/>
</div>
)
}
server code ํ์ด์ง=>> ๐ฆ๐ฆ Streaming Server