본문

IT로그/프로그래밍

[웹 사이트에서 YouTube 업로드 API 사용하기] - 2. YouTube 업로드 구현 및 테스트

1. 시작하기 전에 


2. 리소스 다운로드 및 프로젝트에 추가

https://github.com/youtube/api-samples

위 링크에서 소스파일을 다운로드하면 언어별로 유튜브 api를 구현되어있습니다.

그중에서 자바스크립트용 코드를 이용할건데 먼저 자바스크립트 폴더에서 다음 파일들을 스프링 프로젝트에 추가해줍니다.

js 파일 : auth.js , cors_upload.js, upload_video.js

css 파일 : upload_video.css


3. 테스트 페이지 작성

<youtubeUploadTest.jsp>

위에서 추가한 리소스 파일들의 링크와 부트스트랩 + fontawesome의 CDN을 페이지에 등록.

<html>

<head>
   <title>Youtube Upload Test</title>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <link rel="stylesheet" href="/resources/css/upload_video.css">
   <!-- 부트스트랩 & FontAwesome -->
   <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css" integrity="sha384-Smlep5jCw/wG7hdkwQ/Z5nLIefveQRIY9nfy6xoR1uRYBtpZgI6339F5dgvm/e9B" crossorigin="anonymous">
   <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.1/css/all.css" integrity="sha384-O8whS3fhG2OnA5Kas0Y9l3cfpmYjapjI0E4theH4iuMD+pLhbf6JI0jIMfYcK3yZ" crossorigin="anonymous">
</head>

<style>
  #inputarea{
     border: 1px solid #ccc;
     padding : 10px;
     margin-top: 30px;
     height: 400px;
  }
	
  #main-container {
     padding : 50px 20px;
  }

</style>

<body>
    
  <div id="main-container">
     ...
  </div>
    
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js" integrity="sha384-o+RDsa0aLu++PJvFqy8fFScvbHFLtbvScb8AjopnFD+iEQ7wo/CG0xlczd+2O/em" crossorigin="anonymous"></script>

  <script src="//apis.google.com/js/client:plusone.js"></script>
  <script src="/resources/js/cors_upload.js"></script>
  <script src="/resources/js/upload_video.js"></script>
  <script src="/resources/js/auth.js"></script>
</body>
</html>


<youtubeUploadTest.jsp의 main-container>

<버튼>

<button class="btn btn-primary" data-toggle="modal" data-target="#youtubeModal"><i class="fab fa-youtube" ></i></button>


<modal>

상단 IMPORTANT 주석 아래에 있는 span 태그 data-clientid 값에 이전 글에서 생성한 클라이언트 ID를 입력

<div id="youtubeModal" class="modal modal-outline-secondary fade" role="dialog">
   <div class="modal-dialog">
     <!-- Modal content -->
     <div class="modal-content">
       <div class="modal-header">
         <h4 class="modal-title">Youtube Upload</h4>
         <button type="button" class="close" data-dismiss="modal">&times;</button>
       </div>
            
       <div class="modal-body">
         <div class="form-group">
            <span id="signinButton" class="pre-sign-in">
            <!-- IMPORTANT: Replace the value of the <code>data-clientid</code>
            attribute in the following tag with your project's client ID. -->
              <span
                class="g-signin"
                data-callback="signinCallback"
                data-clientid="your clientID" 
                data-cookiepolicy="single_host_origin"
                data-scope="https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube">
              </span>
            </span>
                </div>
            
                <div class="post-sign-in">             
                <div class="form-group">
                    <label for="title">제목:</label>
                    <input id="title" class="form-control" type="text" placeholder="동영상 제목">
                </div>
                <div class="form-group">
                    <label for="description">설명:</label>
                    <textarea id="description" class="form-control" placeholder="동영상 설명"></textarea>
                </div>
                <div class="form-group">
                    <label for="privacy-status">공개 설정:</label>
                    <select id="privacy-status">
                    <option value="public">공개</option>
                    <option value="unlisted" selected>미등록</option>
                    <option value="private">비공개</option>
                    </select>
                </div>
            
                <div>
                
                <div class="form-group">
                    <div class="input-group mb-3">
                    <div class="input-group-prepend">
                        <span class="input-group-text">Upload</span>
                    </div>
                    <div class="custom-file">
                        <input type="file" class="custom-file-input" id="file-youtube" accept="video/*" onchange="$('label[for=file-youtube]').text($(this).val().split('\\').pop())">
                        <label class="custom-file-label" for="file-youtube">파일 선택</label>
                    </div>
                    </div>
                </div>	
                
                <div class="form-group text-right">
                    <button id="btn-ytb-upload" class="btn btn-outline-primary">업로드하기</button>
                </div>
                
                <div class="during-upload">
                    <div class="progress">
                        <div id='progress-bar-youtube' class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
                    </div>
                    <span id="bytes-transferred"></span>/<span id="total-bytes"></span> bytes   
                </div>
            
                <div class="post-upload">
                    <p>Uploaded video with id <span id="video-id"></span>. Polling for status...</p>
                    <ul id="post-upload-status"></ul>
                </div>
                
                </div>			    
                </div>
            </div>
        
            <div class="modal-footer justify-content-start">
                <p id="disclaimer">By uploading a video, you certify that you own all rights to the content or that you are authorized by the owner to make the content publicly available on YouTube, and that it otherwise complies with the YouTube Terms of Service located at <a href="https://www.youtube.com/t/terms" target="_blank">https://www.youtube.com/t/terms</a></p>
            </div>
        </div>
    </div>
</div>


<에디터>

유튜브에 동영상을 업로드 한 후 게시판 첨부까지의 작업을 테스트 하기 위해 간단한 에디터를 만들었습니다.

<div id="inputarea" contenteditable="true">
   <p><br></p>
</div>


4. js 파일 수정

<auth.js>

OAUTH2_CLIENT_ID에 클라이언트 ID 등록.

 

<upload_video.js>

default 태그가 'youtube-cors-upload'로 되어있는데 다른 태그로 변경하려면  40번 라인의 this.tags 에 등록된 값을 변경.

 

인증정보가 있을경우 실행되는 코드입니다.

'#button' -> modal 내 업로드 버튼의 id 값으로 변경.

이 글의 코드에서는 '#btn-ytb-upload' 으로 변경

 

동영상의 메타데이터를 설정하는 부분입니다.

원본 소스 코드의 경우 snippet의 description이 "$('#description').text()" 로 되어있는데 동영상 설명을 변경하여도 적용이 안되는 문제가 있어서  .text()를  .val()로 수정했습니다.

 

- 업로드버튼을 클릭 했을때의 처리

<수정 전>


<수정 후>

UploadVideo.prototype.handleUploadClicked = function() {
if($('#file-youtube').get(0).files.length === 0) {
	alert('업로드할 동영상을 선택해주세요.');
	return;
}

if($('#title').val() === '') {
	alert('동영상의 제목을 입력해주세요.');
	return;
}
$('#btn-ytb-upload').attr('disabled', true);
this.uploadFile($('#file-youtube').get(0).files[0]);
};

원본 소스 코드에서는 업로드 버튼을 비활성화 시키고 동영상 파일 데이터를 uploadFile 메소드로 넘겨서 업로드를 진행합니다. 

이 과정에서 추가적으로 필요한 작업이 있다면 추가하면 됩니다.

이 글에서는 동영상 제목과 동영상 파일이 없는 경우 업로드를 막기 위한 작업을 추가했습니다.


- 업로드가 진행될 때와 완료 후 처리

<수정 전>


<수정 후 onProgress>

   onProgress: function(data) {

      var currentTime = Date.now();
      var bytesUploaded = data.loaded;
      var totalBytes = data.total;

      // The times are in millis, so we need to divide by 1000 to get seconds.
      var bytesPerSecond = bytesUploaded / ((currentTime - this.uploadStartTime) / 1000);
      var estimatedSecondsRemaining = (totalBytes - bytesUploaded) / bytesPerSecond;
      var percentageComplete = Math.floor(bytesUploaded/ totalBytes * 100);

//      $('#upload-progress').attr({
//        value: bytesUploaded,
//        max: totalBytes
//      });
       
  $('#progress-bar-youtube').css('width', percentageComplete+'%');
  $('#progress-bar-youtube').attr("aria-valuenow", percentageComplete);
  $('#progress-bar-youtube').text(percentageComplete+"%");	
 
//$('#percent-transferred').text(percentageComplete);
  $('#bytes-transferred').text(bytesUploaded);
  $('#total-bytes').text(totalBytes);

  $('.during-upload').show();
}.bind(this), 

업로드가 진행될때 호출되는 메소드 입니다.

업로드 진행 정보를 표시하는 작업을 하는데 부트스트랩의 커스텀 progress bar로 변경 후 그에 맞게 수정하였습니다.


<수정 후 onComplete>

onComplete: function(data) {
      var uploadResponse = JSON.parse(data);
      this.videoId = uploadResponse.id;
      //var videoThumb = uploadResponse.snippet.thumbnails.high.url;
      //$('#video-id').text(this.videoId);
      $('#inputarea').append('<p class="youtube"><iframe width="560" height="315" src="https://www.youtube.com/embed/' + this.videoId + '" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe><br></p><br>'); //게시글에 등록
      modalDataInit();      
//      $('.post-upload').show();
//      this.pollForVideoStatus();
    }.bind(this)

업로드가 완료됐을때 호출되는 메소드 입니다.

업로드가 완료되면 video ID값을 이용하여 iframe 태그로 만든 다음 게시글에 입력하도록 수정하였습니다.

이 글의 코드에서는 실행을 막아놓은 pollForVideoStatus 메소드는 업로드 이후 영상 처리상태를 체크하는 메소드입니다.

이 메소드의 영상 처리 완료시 진행되는 부분에서 게시글에 등록하도록 구현해도 됩니다만 처리과정에서 걸리는 시간이 조금 긴 편이기 때문에 등록화면에서 사용자를 계속 기다리게 하는것보다는 등록 후 다른 작업을 하며 기다릴수 있도록 onComplete 메소드에서 게시글에 등록하고 업로드 과정을 마치도록 수정했습니다.


- 업로드 이후 modal 초기화

function modalDataInit(){
	
    jQuery('#youtubeModal').modal('hide');
    //$('#id').modal('hide'); 의 경우 외부 js파일에서 제대로 실행이 되지 않아 $대신 jQuery 사용

    $('#title').val("");
    $('#description').val("");
    $('#file-youtube').val("");
    $('label[for=file-youtube]').text("파일 선택");
    
    $('#progress-bar-youtube').css('width', '0%');
    $('#progress-bar-youtube').attr("aria-valuenow", 0);
    $('#progress-bar-youtube').text("");	
    
    $('#btn-ytb-upload').attr('disabled', false);
    
    $('#bytes-transferred').text(0);
    $('#total-bytes').text(0);
    $('.during-upload').hide();
    
}

업로드가 진행되며 변경되었던 요소들의 값을 초기화하는 메소드를 추가했습니다.


5. YouTube 업로드 테스트

모달 버튼을 클릭하면 보이는 구글로그인 버튼을 눌러 인증을 진행합니다.
아무것도 뜨지 않는다면 브라우저에서 구글로 접속하여 로그아웃한 뒤 진행하면 됩니다.
구글 로그인 버튼을 눌렀을때 401에러가 나온다면 auth.js 파일과 modal에 입력한 클라이언트 ID를 다시 확인합니다.  

인증이 성공적으로 완료되면 아래와 같이 업로드 폼이 보여집니다.

<업로드 중일때의 화면>


업로드가 완료되면 에디터에 입력이 됩니다.

업로드 직후에는 아직 영상처리과정이 진행중이기 때문에 정상적으로 표시되지 않습니다.

영상처리과정이 완료된 후 재생을 하면 정상적으로 재생이 됩니다.

테스트 과정에서 문제가 없었다면 버튼과 modal을 게시판 소스에 추가하여 사용하면 됩니다.

댓글 1

티스토리 툴바