Video Upload

0_CyberLover_0·2022년 4월 28일
0

Node.JS #05

목록 보기
18/19

샘플로 쓸 영상을 하나 다운로드 해놨다.

https://sample-videos.com/

여기서 쉽게 구할수 있다. 실험할 용량과 형식에 맞게 구할 수 있다.

이제 video를 업로드 할 거다. video에는 파일이 필요하다.

먼저 views폴더의 upload.pug에 들어가서

block content 
    if errorMessage 
        span=errorMessage
    form(method="POST")
        label(for="video") Video File
        input(type="file", accept="video/*",requried,id="video",name="video")

video에 쓸 label을 만든다. file로 해도 상관없다.

그리고 Video File을 추가한다. 아래에는 typefileinput을 만든다.

accept에는 모든 종류의 video형식을 쓴다. required를 추가해주는 걸 잊지 않는다.

labelid를 활용하니까 꼭 id를 추가해준다. 그리고 multer middleware 사용을 위해 name을 추가한다. video를 써줬다.

새로고침을 해보면 영상 파일을 선택하지 않으면 업로드 하지 못한다.

그리고 샘플 영상을 첨부해서 업로드를 해준다.

그러기 전에 controller에 어떤 일이 생길지 안다.

videoRouter코드를 수정 해준다.

videoRouter
  .route("/upload")
  .all(protectorMiddleware)
  .get(getUpload)
  .post(uploadFiles.single("video"), postUpload);

여기에 만들어 놓은 uploadFiles middleware를 추가 해준다.

그리고 form에서 filename을 추가하는걸 잊어선 안된다.filenamevideo이다.

이제 multer documenatation에서 볼게 있다.

https://www.npmjs.com/package/multer

추가적으로 보낼수 있는 option들이 있다. 이 옵션들 중에 fileSize라는걸 사용할거다.

이걸 가지고 2개의 middleware에서 avatar파일의 업로드 용량을 1MB이하로 하고
video파일의 업로드 용량을 10MB이하로 제한하면 좋을것 같다.

사람들이 용량이 큰 영상을 올리지 않게 말이다.

그래서 이 방법 대신에 2개의 middleware를 만든다.

export const avatarUpload = multer({
  dest: "uploads/avatars/",
  limits: {
    fileSize: 3000000,
  },
});
export const videoUpload = multer({
  dest: "uploads/videos/",
  limits: {
    fileSize: 10000000,
  },
});

하나는 avatar업로드 하는걸로 만든다. uploads/avatars에 저장하도록 만든다.

다른 하나는 videoUpload로 만든다. 그리고 uploads/videos에 저장하도록 한다.

그리고 두곳 모두 limits를 추가한다. avatar,videolimitsfileSize를 쓴다.

그리고 각각 용량을 설정해 주었다. 기본(단위)으로 바이트로 설정되어 있다.

이제 이보다 용량이 큰 파일은 업로드 되지 않는다.

테스트를 해본다. 일단 avatarUploadfileSize를 아주 작게 해본다.

3000바이트로 하면 어떻게 되는지 테스트 해보겠다.

새로고침을 하였더니 그전에 에러가 발생하였다. middelware이름을 변경해서 그런것 같다.

userRouter에 들어가보면 더 이상 존재하지 않는 uploadFiles를 사용중이다.

import {
  protectorMiddleware,
  publicOnlyMiddleware,
  avatarUpload,
} from "../middlewares";
userRouter
  .route("/edit")
  .all(protectorMiddleware)
  .get(getEdit)
  .post(avatarUpload.single("avatar"), postEdit);

변경한 이름으로 변경 해준다.

그리고 videoRouteruploadFiles도 존재하지 않으니까

import { protectorMiddleware, videoUpload } from "../middlewares";
videoRouter
  .route("/upload")
  .all(protectorMiddleware)
  .get(getUpload)
  .post(videoUpload.single("video"), postUpload);

videoUpload로 변경해준다. 이제 콘솔에서 확인해 보면 에러가 나지 않는다.

새로고침하고 설정한 용량보다 큰 avatar를 업로드하면 어떻게 되는지 시도해 본다.

파일이 너무 크다고 에러가 났다. 파일이 너무 커서 multer가 허용하지 않고 있다.

이제 이 오류를 사용자에게 제대로 된 메세지로 보여줘야 한다.

그래서 응답을 보내줘야 하는데 나중에 해주기로 한다.

어찌되었든 fileSize limits는 잘 작동하고 있다.

이제 2개의 middleware가 생겼다. 하나는 용량 제한으로 video를 업로드하는거고
다른 하나는 avatar를 업로드 하는거다.

videoController.js에서

export const postUpload = async (req, res) => {
  const file = req.file;
  const { title, description, hashtags } = req.body;
  try {
    await Video.create({
      title,
      description,
      fileUrl: file.path,
      hashtags: Video.formatHashtags(hashtags),
    });

이제 file을 받아서 그리고 file자체가 아니라 file의 경로를 원하니까 fileUrl을 추가하고 file.path을 넣어준다.

multerreq.file을 제공해주는데 file안에 path가 있다는걸 기억한다.

하지만 아직 video안에 fileUrl을 만들지 않았다.

Video.js에서

const videoSchema = new mongoose.Schema({
  title: { type: String, required: true, trim: true, maxLength: 80 },
  fileUrl: { type: String, reqired: true },

file없이는 video를 만들지 못한다. 그리고 테스트 해보기 전에 잊으면 안될게 있다.

upload.pug에서

block content 
    if errorMessage 
        span=errorMessage
    form(method="POST", enctype="multipart/form-data"

multer을 사용해서 파일을 업로드 하고 싶다면 formencoding type을 바꿔 줘야 한다.

edit-progfileformenctype을 추가한 것처럼 똑같이 해주면 된다.

이 작업을 해주지 않으면 multer는 정상 작동하지 않는다.

잘못된 코드를 찾아 헤매도 찾지 못할거다. 그러니 enctypemultipart/form-data인지 꼭 확인하도록 한다.

이제 테스트해 본다. 업로드에 성공했다. DB에서도 video를 찾을수 있다.

db.videos.find({}) 쳐보면 fileUrluploads/videos/파일이름이 나온다.

그리고 uploads폴더에 들어가면 avatarsvideos가 있다.

이전 파일들이 지워지지 않는 문제가 있긴 하다.

multer를 사용해서 uploads 폴더 안 서로 다른 디렉토리에 저장할수 있게 만들었다.

avatarsvideos폴더가 있다. 현재 avatars에는 아무것도 없는데 새로운 avatar를 업로드 하면 생길거다.

이제 업로드한 영상을 재생시켜 본다.

업로드된 영상을 클릭해 보면 예전에 만든대로 id를 가지고 비디오를 찾고 있다.

그리고 video의 데이터가 모두 있다. 이제 여기에 video element를 추가하면 될것 같다.

watch.pug로 가서 video element를 추가한다.

watch.pugvideoControllerrender하고 있는 template이다.

videoControlloer.js에서

export const watch = async (req, res) => {
  const { id } = req.params;
  const video = await Video.findById(id);
  if (!video) {
    return res.status(404).render("404", { pageTitle: "Video not found." });
  }
  return res.render("watch", { pageTitle: video.title, video });
};

DB에서 video를 찾은 다음 그 video를 변수로 보내고 있다.

이 말은 object가 통째로 template에 있다는 거다.

이제 다시 돌아가서 video.fileUrl을 쓴다.

watch.pug에서

block content
   video(src="/" + video.fileUrl)

그리고 path 때문에 작동하지는 않을거다. 그래서 path도 추가해 주었다.

새로고침해서 확인하면 영상이 올라온걸 확인 할수 있다. 여기서 이제 controls를 추가해준다.

block content
   video(src="/" + video.fileUrl,controls

그러면 이제 controls가 생겼고 재생이 된다.

다시 한번 되짚어 보겠다.

middleware를 만들어 봤고 limits설정하는것도 했다. avatarvideo에 각각 원하는 용량으로 제한하면 된다.

watch.pug에서 video도 추가해봤다. 그리고 영상이 실제로 존재하니까 fileURL도 추가해 주었다.

uploadVideo로는 영상을 업로드하고 있다.

그리고 path를 바로 꺼내고 path을 쓸수 있게 변경 해주었다.

videoController.js에서

export const postUpload = async (req, res) => {
  const { path } = req.file;
  const { title, description, hashtags } = req.body;
  try {
    await Video.create({
      title,
      description,
      fileUrl:path,
      hashtags: Video.formatHashtags(hashtags),
    });

그리고 다른 방법은 request.file.path가 있다는 것을 알고 있다.

이것 자체를 바꿀수는 없지만 pathreq.file.path에서 받은뒤

이름을 fileUrl로 바꿀수 있다.

export const postUpload = async (req, res) => {
  const { path: fileUrl } = req.file;
  const { title, description, hashtags } = req.body;
  try {
    await Video.create({
      title,
      description,
      fileUrl,
      hashtags: Video.formatHashtags(hashtags),
    });

그러면 이렇게 바꿀수 있게 된다. 이게 바로 ES6의 힘이다.

profile
꿈꾸는 개발자

0개의 댓글