Youtube上传API和cordova / phonegap

时间:2015-03-29 14:31:52

标签: cordova meteor youtube-api youtube-javascript-api

我正在编写一个cordova应用程序,让用户录制视频并通过他们的API将其上传到youtube。

如果我使用文件输入并通过

访问该文件

$('#file').get(0).files[0]

我收到一个file对象,可以毫无问题地上传。

如果我录制视频,我会收到一个medialist对象。 然后我可以致电window.resolveLocalFileSystemURL( video[0].localURL , success, fail);

在成功回调中,我收到了一个文件列表对象。这也不会被接受。

在这个filelist对象上,我可以调用data.file(success,fail),它最终返回一个文件对象。但是当我尝试上传到youtube时,我收到308错误。

我怀疑它与访问本地文件路径的权限有关。如果有人有这方面的经验,我很乐意听到解决方法。

以下是上传代码:

UploadVideo.prototype.ready = function(accessToken, video) {
    this.accessToken = accessToken;
    this.gapi = gapi;
    this.authenticated = true;
    $this = this;

function result(data){
    function success(data){

        data.name = "VID_20150329_160037.mp4";
        console.log(data)
        $this.uploadFile( data );
    }
    data.file(success)

}
function fail(data){
    console.log(data)
}
window.resolveLocalFileSystemURL( video[0].localURL , result, fail);


//this.uploadFile( $('#file').get(0).files[0] );

// $('#button').on("click", this.handleUploadClicked.bind(this));

5 个答案:

答案 0 :(得分:4)

使用此博客帖子我设法获取元数据和文件上传工作: http://lithostech.com/2013/10/upload-google-youtube-api-v3-cors/

通过在发送之前注销FileTransfer标头信息,我可以看到格式不同:

Content-Disposition: form-data; name="part"
{"snippet":{"title":"Video title","description":"Video description","tags":"Video tags","categoryId":22},"status":{"privacyStatus":"unlisted"}}

应该是:

Content-Disposition: form-data; name=""; filename="file.json"
Content-Type: application/json
{"snippet":{"title":"Video title","description":"Video description","tags":"Video tags","categoryId":22},"status":{"privacyStatus":"unlisted"}}

以下是包含工作元数据的更新版本:

function uploadVideo(fileURL) {
    var options = new FileUploadOptions();
    options.fileKey = 'file';
    options.fileName = fileURL.substr(fileURL.lastIndexOf('/') + 1);
    options.mimeType = 'video/mpg';
    options.chunkedMode = false;
    options.headers = {
        Authorization: 'Bearer ' + accessToken
    };
    options.params = {
        "": {
            snippet: {
                title: 'Video title',
                description: 'Video description',
                tags: 'Video tags',
                categoryId: 22
            },
            status: {
                privacyStatus: 'unlisted'
            }
        }
    };
    var ft = new FileTransfer();
    ft.upload(fileURL, 'https://www.googleapis.com/upload/youtube/v3/videos?part=snippet,status', function (data) {
        console.log('upload success', data);
    }, function (e) {
        console.log('upload error', e);
    }, options, true);
    ft.onprogress = function (progressEvent) {
        console.log('onprogress: ' + ((progressEvent.loaded / progressEvent.total) * 100) + '%');
    };
}

请注意我也稍微修改了我的FileTransfer插件:

FileTransfer.java 第374 - 376行

beforeData.append("Content-Disposition: form-data; name=\"").append(key.toString()).append("\";");
beforeData.append(" filename=\"").append("file.json").append('"').append(LINE_END);
beforeData.append("Content-Type: ").append("application/json").append(LINE_END).append(LINE_END);

修改cordova / phonegap / ionic中的插件后,您需要重新加载它。我这样做是通过删除平台并再次添加它来的:

cordova platform remove android; cordova platform add android;

答案 1 :(得分:2)

我终于开始工作了。我需要使用cordova filetransfer插件

这是代码

function postVideo(accessToken, fileURI) {
  var metadata = {
    snippet: {
      title: "test",
      description: "test",
      tags: ["youtube-cors-upload"],
      categoryId: 21
    },
    status: {
      privacyStatus: "unlisted"
    }
  }

  var options = new FileUploadOptions();
  options.fileKey = "file";
  options.fileName = 'test';
  options.mimeType = "video/mp4";
  options.chunkedMode = false;

  options.headers = {
    Authorization: "Bearer " + accessToken,
    "Access-Control-Allow-Origin": "http://meteor.local"
  };

  var params = new Object();
  params.part = Object.keys(metadata).join(',')

  options.params = params;
  console.log(options)
  var ft = new FileTransfer();
  ft.upload(fileURI, "https://www.googleapis.com/upload/youtube/v3/videos?part=snippet", win, fail, options, true);

  ft.onprogress = function(progressEvent) {
    if (progressEvent.lengthComputable) {
      // console.log(progressEvent)
      // loadingStatus.setPercentage(progressEvent.loaded / progressEvent.total);
    } else {
      console.log('something not loading')
        // loadingStatus.increment();
    }
    console.log(progressEvent.loaded / progressEvent.total);
  };
}

function win(r) {
  console.log(r)
  console.log("Code = " + r.responseCode);
  console.log("Response = " + r.response);
  console.log("Sent = " + r.bytesSent);
}

function fail(error) {
  console.log(error)
    // alert("An error has occurred: Code = " + error.code);
  console.log("upload error source " + error.source);
  console.log("upload error target " + error.target);
}

答案 2 :(得分:0)

感谢您分享信息。

当我想使用cordova插件在设备中上传所选文件时,我遇到了同样的情况。

我的情况不是308错误,但是由cordova-file插件返回的文件数据没有正确的格式作为输入文件HTML的Blob格式。

那么,有一个简单的解决方案来修复问题。它是将文件的数据转换为输入文件HTML的正确Blob格式。

我使用了来自Youtube Data API和参考链接的示例,如下所示:

解决此问题的解决方案的主要思路

1)将文件数据转换为输入文件HTML的Blob格式。
2)修改upload_video.js文件的内容。
3)修改cors_upload.js文件的内容。

解决方案的细节

1)将文件数据转换为输入文件HTML的Blob格式:

○输入内容是cordova-file插件返回的文件
  ○使用FileReader HTML5将文件内容读取为ArrayBuffer   ○使用Blob对象创建包含数据的新内容。

*转换数据示例代码

UploadVideo.prototype.convertToBlob = function (file, onSuccess) {
          var reader = new FileReader();
          reader.onload = (function (event) {
            var blob = new Blob([new Uint8Array(this.result)], { type: file.type });
            onSuccess(blob);
          });
          reader.readAsArrayBuffer(file);
        };


2)修改upload_video.js文件的内容:

○创建" myFile"存储所选文件的UploadVideo对象的属性 ○检索cordova-file插件返回的数据内容并将其转换为Blob格式。

*读取文件内容并将内容转换为Blob示例代码

 var self_ = this; //the instance of UploadVideo object
        window.resolveLocalFileSystemURL(fileUri, function (fileEntry) {
              //success
              fileEntry.file(function(file){
                   //Store selected file to re-use when upload event
            self_.myFile = file;
            //We could use file as input of  convertToBlob ()
            self_.convertToBlob (file, function(blob){
                self_.myFile.newBlob  = blob;
            });
              });
          }, function (response) {
              //error
          });

○需要确保新的Blob内容已经用于在UploadVideo.prototype.handleUploadClicked()方法中输入this.uploadFile()。

* handleUploadClicked()

中的Modifiy源代码
Replace:
   this.uploadFile($('#file').get(0).files[0]);
By new:
   this.uploadFile(this.myFile);



3)修改cors_upload.js文件的内容:

○从MediaUploader.prototype.sendFile_()方法修改新的上传内容

*修改sendFile _()

中的源代码
Replace:
   var content = this.file;
By new:
   var content = this.file.newBlob;



这是我解决这个问题的全部解决方案。简单修改源代码。

最诚挚的问候,
Dang Quynh。

答案 3 :(得分:0)

继续关注Kim T's answer,以下是如何让它在iOS上运行:

使用此pull request中的代码修改位于xCode项目的CDVFileTransfer.m目录中的Plugins文件。修改如下所示:

<强>的src / IOS / CDVFileTransfer.m

@@ -25,6 +25,7 @@ Licensed to the Apache Software Foundation (ASF) under one
+#import <Foundation/NSJSONSerialization.h>

@@ -203,6 +204,11 @@ - (NSURLRequest*)requestForUploadCommand:(CDVInvokedUrlCommand*)command fileData
+        // if it is a valid json object get the NSString representation
 +        if ([NSJSONSerialization isValidJSONObject:val]){
 +            NSData *jsonData = [NSJSONSerialization dataWithJSONObject:val options:NSJSONWritingPrettyPrinted error:nil];
 +            val = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
 +        }

然后在同一个文件中,在requestForUploadCommand函数中迭代options中的,更改此行:

[postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];

对此:

[postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"file.json\"\r\nContent-Type: application/json\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];

这可能没关系,但在使用上述拉取请求中的代码时,我将options:NSJSONWritingPrettyPrinted更改为options:0

一旦我做了这些更改,就在xCode中重新构建项目并在我妻子的iPad上启动它,将视频上传到YouTube,使用元标记信息就像魅力一样。

答案 4 :(得分:-1)

接受的答案是错误的,不起作用。正确的答案是你应该使用这里详细介绍的2部分可恢复上传方法: https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol

示例:

  var videoResourceYT = //yt video resource goes here
  }

  videoResourceYT = JSON.stringify(videoResourceYT)
  var ftoptions = new FileUploadOptions();
  var ft = new FileTransfer();
  $.ajax({
    url:"https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status",
    method:"POST",
    data: videoResourceYT,
    contentType:"application/json; charset=UTF-8",
        beforeSend: function (request) {
              request.setRequestHeader("Authorization", "Bearer " + token);
              request.setRequestHeader("X-Upload-Content-Length", /*file length, not actually needed*/);
              request.setRequestHeader("X-Upload-Content-Type", "video/*");
        },
        success: function(ytuploadData, ytTextStatus, ytRequest){
          var nextUrlYT = ytRequest.getResponseHeader('Location');
          console.log(nextUrlYT)

          ftoptions.mimeType = "video/*";
          ftoptions.chunkedMode = false;
          ftoptions.headers = {
              "Authorization": 'Bearer ' + token,
              "Content-Type": "video/*"
          };
          ftoptions.httpMethod = "PUT"


          //?part=snippet,status
          ft.upload(/*options go here*/);
        },
        error: function(e1,e2,e3){
        }
  })