Я пытаюсь загрузить с помощью API YouTube - PullRequest
0 голосов
/ 18 марта 2019

Я написал код для загрузки видео с помощью API YouTube.

Я скачал файлы из этого репозитория и добавил их в свой проект.

Но я не получил то, что хотел, вместо этого я получил ошибку, но не знаю почему.

Иерархия папок: dynamic web project directory

youtubeUploadTest.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <link rel="stylesheet" href="../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">
<title>Insert title here</title>
</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">
   <button class="btn btn-primary" data-toggle="modal" data-target="#youtubeModal"><i class="fab fa-youtube" ></i></button>
   <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="857337372611-0um3gu3dtmrnj3hg2fahurgrm6ah9c6a.apps.googleusercontent.com" 
                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  
                </div>
        </div>
    </div>
</div>

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

  </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="../js/cors_upload.js"></script>
  <script src="../js/upload_video.js"></script>
  <script src="../js/auth.js"></script>
</body>
</html>

auth.js

// The client ID is obtained from the {{ Google Cloud Console }}
// at {{ https://cloud.google.com/console }}.
// If you run this code from a server other than http://localhost,
// you need to register your own client ID.
var OAUTH2_CLIENT_ID = '857337372611-0um3gu3dtmrnj3hg2fahurgrm6ah9c6a.apps.googleusercontent.com';
var OAUTH2_SCOPES = [
  'https://www.googleapis.com/auth/youtube'
];

// Upon loading, the Google APIs JS client automatically invokes this callback.
googleApiClientReady = function() {
  gapi.auth.init(function() {
    window.setTimeout(checkAuth, 1);
  });
}

// Attempt the immediate OAuth 2.0 client flow as soon as the page loads.
// If the currently logged-in Google Account has previously authorized
// the client specified as the OAUTH2_CLIENT_ID, then the authorization
// succeeds with no user intervention. Otherwise, it fails and the
// user interface that prompts for authorization needs to display.
function checkAuth() {
  gapi.auth.authorize({
    client_id: OAUTH2_CLIENT_ID,
    scope: OAUTH2_SCOPES,
    immediate: true
  }, handleAuthResult);
}

// Handle the result of a gapi.auth.authorize() call.
function handleAuthResult(authResult) {
  if (authResult && !authResult.error) {
    // Authorization was successful. Hide authorization prompts and show
    // content that should be visible after authorization succeeds.
    $('.pre-auth').hide();
    $('.post-auth').show();
    loadAPIClientInterfaces();
  } else {
    // Make the #login-link clickable. Attempt a non-immediate OAuth 2.0
    // client flow. The current function is called when that flow completes.
    $('#login-link').click(function() {
      gapi.auth.authorize({
        client_id: OAUTH2_CLIENT_ID,
        scope: OAUTH2_SCOPES,
        immediate: false
        }, handleAuthResult);
    });
  }
}

// Load the client interfaces for the YouTube Analytics and Data APIs, which
// are required to use the Google APIs JS client. More info is available at
// https://developers.google.com/api-client-library/javascript/dev/dev_jscript#loading-the-client-library-and-the-api
function loadAPIClientInterfaces() {
  gapi.client.load('youtube', 'v3', function() {
    handleAPILoaded();
  });
}

upload_video.js

/*
Copyright 2015 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var signinCallback = function (result){
  if(result.access_token) {
    var uploadVideo = new UploadVideo();
    uploadVideo.ready(result.access_token);
  }
};

var STATUS_POLLING_INTERVAL_MILLIS = 60 * 1000; // One minute.


/**
 * YouTube video uploader class
 *
 * @constructor
 */
var UploadVideo = function() {
  /**
   * The array of tags for the new YouTube video.
   *
   * @attribute tags
   * @type Array.<string>
   * @default ['google-cors-upload']
   */
  this.tags = ['youtube-cors-upload'];

  /**
   * The numeric YouTube
   * [category id](https://developers.google.com/apis-explorer/#p/youtube/v3/youtube.videoCategories.list?part=snippet&regionCode=us).
   *
   * @attribute categoryId
   * @type number
   * @default 22
   */
  this.categoryId = 22;

  /**
   * The id of the new video.
   *
   * @attribute videoId
   * @type string
   * @default ''
   */
  this.videoId = '';

  this.uploadStartTime = 0;
};


UploadVideo.prototype.ready = function(accessToken) {
  this.accessToken = accessToken;
  this.gapi = gapi;
  this.authenticated = true;
  this.gapi.client.request({
    path: '/youtube/v3/channels',
    params: {
      part: 'snippet',
      mine: true
    },
    callback: function(response) {
      if (response.error) {
        console.log(response.error.message);
      } else {
        $('#channel-name').text(response.items[0].snippet.title);
        $('#channel-thumbnail').attr('src', response.items[0].snippet.thumbnails.default.url);

        $('.pre-sign-in').hide();
        $('.post-sign-in').show();
      }
    }.bind(this)
  });
  $('#btn-ytb-upload').on("click", this.handleUploadClicked.bind(this));
};

/**
 * Uploads a video file to YouTube.
 *
 * @method uploadFile
 * @param {object} file File object corresponding to the video to upload.
 */
UploadVideo.prototype.uploadFile = function(file) {
  var metadata = {
    snippet: {
      title: $('#title').val(),
      description: $('#description').val(),
      tags: this.tags,
      categoryId: this.categoryId
    },
    status: {
      privacyStatus: $('#privacy-status option:selected').val()
    }
  };
  var uploader = new MediaUploader({
    baseUrl: 'https://www.googleapis.com/upload/youtube/v3/videos',
    file: file,
    token: this.accessToken,
    metadata: metadata,
    params: {
      part: Object.keys(metadata).join(',')
    },
    onError: function(data) {
      var message = data;
      // Assuming the error is raised by the YouTube API, data will be
      // a JSON string with error.message set. That may not be the
      // only time onError will be raised, though.
      try {
        var errorResponse = JSON.parse(data);
        message = errorResponse.error.message;
      } finally {
        alert(message);
      }
    }.bind(this),
    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),
    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)
  });
// This won't correspond to the *exact* start of the upload, but it should be close enough.
  this.uploadStartTime = Date.now();
  uploader.upload();
};

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]);
};

UploadVideo.prototype.pollForVideoStatus = function() {
  this.gapi.client.request({
    path: '/youtube/v3/videos',
    params: {
      part: 'status,player',
      id: this.videoId
    },
    callback: function(response) {
      if (response.error) {
        // The status polling failed.
        console.log(response.error.message);
        setTimeout(this.pollForVideoStatus.bind(this), STATUS_POLLING_INTERVAL_MILLIS);
      } else {
        var uploadStatus = response.items[0].status.uploadStatus;
        switch (uploadStatus) {
          // This is a non-final status, so we need to poll again.
          case 'uploaded':
            $('#post-upload-status').append('<li>Upload status: ' + uploadStatus + '</li>');
            setTimeout(this.pollForVideoStatus.bind(this), STATUS_POLLING_INTERVAL_MILLIS);
            break;
          // The video was successfully transcoded and is available.
          case 'processed':
            $('#player').append(response.items[0].player.embedHtml);
            $('#post-upload-status').append('<li>Final status.</li>');
            break;
          // All other statuses indicate a permanent transcoding failure.
          default:
            $('#post-upload-status').append('<li>Transcoding failed.</li>');
            break;
        }
      }
    }.bind(this)
  });
};


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();

}

Это то, что я ожидал:

I want this

Вместо этого я получил это:

my result screen

В веб-консоли отображается следующее:

не удалось загрузить ресурс, сервер ответил со статусом 404 (не найден) https://apis.google.com/u/0/_/widget/render/signin?usegapi=1&clientid=857337372611-0um3gu3dtmrnj3hg2fahurgrm6ah9c6a.apps.googleusercontent.com&cookiepolicy=single_host_origin&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.upload%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube&origin=http%3A%2F%2Flocalhost%3A8080&url=http%3A%2F%2Flocalhost%3A8080%2Fupload%2Fjsp%2FyoutubeUploadTest.jsp&gsrc=3p&ic=1&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.ko.qxUBKjIEJT0.O%2Fam%3DwQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCNdSZ1FZQPVnT2uJ6sxICSRQCKqHA%2Fm%3D__features__#_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe%2C_renderstart%2Concircled%2Cdrefresh%2Cerefresh%2Conauth%2Conload&id=I0_1552916726606&_gfid=I0_1552916726606&parent=http%3A%2F%2Flocalhost%3A8080&pfname=&rpctoken=53065803

Что не так?authorized redirect uris

Я неверно представил разрешенное происхождение JavaScript?или авторизованные URI перенаправления?

Это экран согласия OAuth: OAuth consent screen

Я не заполнил утвержденный домен, поскольку у него нет домена.Это из-за этого?

...