我正在编写一个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));
答案 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){
}
})