问题描述
我正在尝试构建一个将视频上传到YouTube的服务器应用程序。在我的服务器应用程序中,用户可以直接将视频上传到我的YouTube频道以将其公开。
- 我的应用程序的客户端部分获取视频并上传它到我的服务器。
- 然后我的服务器使用YouTube API将视频上传到我的YouTube频道。 b
$ b为了完成这项工作,我创建了一个虚拟Web应用程序,它可以捕获生成的刷新标记,并将它存储在
key.txt
文件中。{access_token:MYTOKEN,token_type:承载者,expires_in:3600,created:1435654774}
upload_video.php
脚本会自动更新<$如果access_token
过期,c $ c>key.txt文件。这是upload_video.php
的代码:$ key = file_get_contents ( 'key.txt');
$ application_name ='YouTube_Upload';
$ client_secret ='MY_CLIENT_SECRET';
$ client_id ='MY_CLIENT_ID';
$ scope = array('https://www.googleapis.com/auth/youtube.upload','https://www.googleapis.com/auth/youtube','https:// www。 googleapis.com/auth/youtubepartner');
$ videoPath =Test.f4v;
$ videoTitle =教程视频;
$ videoDescription =关于如何上传到YouTube的视频教程;
$ videoCategory =22;
$ videoTags = array(youtube,tutorial);
尝试{
//客户端初始化
$客户端=新建Google_Client();
$ client-> setApplicationName($ application_name);
$ client-> setClientId($ client_id);
$ client-> setAccessType('offline');
$ client-> setAccessToken($ key);
$ client-> setScopes($ scope);
$ client-> setClientSecret($ client_secret);
if($ client-> getAccessToken()){
/ **
*检查访问令牌是否已过期。如果是这样,请获取一个新文件并将其保存以备将来使用。
* /
if($ client-> isAccessTokenExpired()){
$ newToken = json_decode($ client-> getAccessToken());
$ client-> refreshToken($ newToken-> refresh_token);
file_put_contents('key.txt',$ client-> getAccessToken());
}
$ youtube =新Google_Service_YouTube($ client);
//创建一个包含标题,描述,标签和类别ID的snipet
$ snippet = new Google_Service_YouTube_VideoSnippet();
$ snippet-> setTitle($ videoTitle);
$ snippet-> setDescription($ videoDescription);
$ snippet-> setCategoryId($ videoCategory);
$ snippet-> setTags($ videoTags);
//创建隐私状态的视频状态。选项是公开,私人和不公开。
$ status = new Google_Service_YouTube_VideoStatus();
$ status-> setPrivacyStatus('unlisted');
//创建一个带有片段和状态的YouTube视频
$ video = new Google_Service_YouTube_Video();
$ video-> setSnippet($ snippet);
$ video-> setStatus($ status);
//每个数据块的大小(以字节为单位)。将其设置得更高会导致更快的上传(更少的块,
//用于可靠的连接)。将它设置得更低会导致更好的恢复(细粒度块)
$ chunkSizeBytes = 1 * 1024 * 1024;
//将defer标志设置为true,告诉客户端返回一个可以被称为
//的请求 - > execute();而不是立即进行API调用。
$ client-> setDefer(true);
//创建一个请求API的videos.insert方法来创建和上传视频。
$ insertRequest = $ youtube-> videos-> insert(status,snippet,$ video);
//为可恢复的上传创建一个MediaFileUpload对象。
$ media = new Google_Http_MediaFileUpload(
$ client,
$ insertRequest,
'video / *',
null,
true,
$ chunkSizeBytes
);
$ media-> setFileSize(filesize($ videoPath));
//读取媒体文件并按块分块上传。
$ status = false;
$ handle = fopen($ videoPath,rb);
while(!$ status&&!feof($ handle)){
$ chunk = fread($ handle,$ chunkSizeBytes);
$ status = $ media-> nextChunk($ chunk);
}
fclose($ handle);
$ b / **
*如果($ status-> status ['uploadStatus'] =='uploaded')视频已成功上传
* /
) {
//为成功上传而执行的操作
// ......
}
//如果想在文件之后进行其他调用上传,将setDefer设置回false
$ client-> setDefer(true);
} else {
// @TODO记录错误
echo'创建客户端时出现问题';
}
} catch(Google_Service_Exception $ e){
打印Google_Service_Exception。$ e-> getCode()。 message is。$ e-> getMessage();
printStack trace is。$ e-> getTraceAsString();
} catch(Exception $ e){
打印Exception。$ e-> getCode()。 message is。$ e-> getMessage();
printStack trace is。$ e-> getTraceAsString();
}
脚本运行时,会引发此异常:
异常0消息无法启动可恢复上载(HTTP 400:全局,上传必须发送到上传URL。重新发送此请求https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable)堆栈跟踪为
(第281行)在
#0 D:\xampp\htdocs\youtube\\ \\ src\Google\Http\MediaFileUpload.php(136):Google_Http_MediaFileUpload-> getResumeUri()
#1 D:\xampp\htdocs\youtube\resumable_upload.php(100): Google_Http_MediaFileUpload-> nextChunk('\x00\x00\x00\x1Cftypf4v \x00\x00\x00 ...')
#2 {main}
getResumeUri()> Google_Http_MediaFileUpload ,我有var转储来自google的响应
Google_Http_Request对象
(
[batc hHeaders:Google_Http_Request:private] => Array
(
[Content-Type] => application / http
[Content-Transfer-Encoding] =>二进制
[MIME-Version] => 1.0
)
[queryParams:protected] =>数组
(
[part] =>状态,片段
[uploadType] =>可恢复
)
[requestMethod:protected] => ; POST
[requestHeaders:protected] =>数组
(
[content-type] => application / json; charset = UTF-8
[authorization] =>承载XXXXXXXXXXXXXXXX
[content-length] => ; 187
[x-upload-content-type] => video / *
[x-upload-content-length] => 10201286
[expect] =>
)
[baseComponent:protected] => https://www.googleapis.com//upload
[path:protected] => / youtube / v3 / videos
[postBody:protected] => {snippet:{categoryId:22,description:关于如何上传到YouTube的视频教程,tags:[youtube,tutorial],title:A教程视频},status:{privacyStatus:unlisted}}
[userAgent:protected] =>
[canGzip:protected] =>
[responseHttpCode:protected] => 400
[responseHeaders:protected] => Array
(
[x-guploader-uploadid] => XXXXXXXXXXXXXXXXXXXXXXXXXX
[位置] => https://www.googleapis.com/upload/youtube/v3/videos?part = status,snippet& uploadType = resumable
[vary] => Origin
X-Origin
[content-type] => application / json; charset = UTF-8
[content-length] => 468
[date] => 2015年7月10日星期五09:54:30 GMT
[server] => UploadServer
[alternate-protocol ] => 443:quic,p = 1
)
[responseBody:protected] => {
error:{
errors:[
{
domain:global,
reason:wrongUrlForUpload,
消息:必须将上传内容发送到上传网址。请将此请求重新发送到https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable
}
],
code:400,
message:上传文件必须发送至上传网址,重新发送至https:// www .googleapis.com / upload / youtube / v3 / videos?part = status,snippet& uploadType = resumable
}
}
[expectedClass:protected] => Google_Service_YouTube_Video
[expectedRaw:protected] =>
[accessKey] =>
)
有什么不对?
感谢任何帮助,并对错误的英语感到抱歉。解决方案这似乎是PHP Client Library Google API。转到GOOGLE_LIB_PATH / Http / MediaFileUpload.php并替换此行:
$ this-> request-> setBaseComponent($ base /'upload');
有了这个:
$ this-> request-> setBaseComponent($ base。'upload');
重试并分享结果。我遇到了Google Pubsub API的类似问题,其中由库设置的API路径不正确。
I'm trying to build a server application for uploading videos to YouTube. In my server application, the user can upload a video directly to my YouTube channel to make it public.
- The client part of my application acquires the video and uploads it to my server.
- My server then uses YouTube API to upload the video to my YouTube channel.
To make this work, I created a dummy Web Application that can capture the refresh token generated and I have stored it in a
key.txt
file{"access_token":"MYTOKEN","token_type":"Bearer","expires_in":3600,"created":1435654774}
The
upload_video.php
script will automatically update"key.txt"
file ifaccess_token
is out of date. This is the code fromupload_video.php
:$key = file_get_contents('key.txt'); $application_name = 'YouTube_Upload'; $client_secret = 'MY_CLIENT_SECRET'; $client_id = 'MY_CLIENT_ID'; $scope = array('https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/auth/youtube', 'https://www.googleapis.com/auth/youtubepartner'); $videoPath = "Test.f4v"; $videoTitle = "A tutorial video"; $videoDescription = "A video tutorial on how to upload to YouTube"; $videoCategory = "22"; $videoTags = array("youtube", "tutorial"); try{ // Client init $client = new Google_Client(); $client->setApplicationName($application_name); $client->setClientId($client_id); $client->setAccessType('offline'); $client->setAccessToken($key); $client->setScopes($scope); $client->setClientSecret($client_secret); if ($client->getAccessToken()) { /** * Check to see if access token has expired. If so, get a new one and save it to file for future use. */ if($client->isAccessTokenExpired()) { $newToken = json_decode($client->getAccessToken()); $client->refreshToken($newToken->refresh_token); file_put_contents('key.txt', $client->getAccessToken()); } $youtube = new Google_Service_YouTube($client); // Create a snipet with title, description, tags and category id $snippet = new Google_Service_YouTube_VideoSnippet(); $snippet->setTitle($videoTitle); $snippet->setDescription($videoDescription); $snippet->setCategoryId($videoCategory); $snippet->setTags($videoTags); // Create a video status with privacy status. Options are "public", "private" and "unlisted". $status = new Google_Service_YouTube_VideoStatus(); $status->setPrivacyStatus('unlisted'); // Create a YouTube video with snippet and status $video = new Google_Service_YouTube_Video(); $video->setSnippet($snippet); $video->setStatus($status); // Size of each chunk of data in bytes. Setting it higher leads faster upload (less chunks, // for reliable connections). Setting it lower leads better recovery (fine-grained chunks) $chunkSizeBytes = 1 * 1024 * 1024; // Setting the defer flag to true tells the client to return a request which can be called // with ->execute(); instead of making the API call immediately. $client->setDefer(true); // Create a request for the API's videos.insert method to create and upload the video. $insertRequest = $youtube->videos->insert("status,snippet", $video); // Create a MediaFileUpload object for resumable uploads. $media = new Google_Http_MediaFileUpload( $client, $insertRequest, 'video/*', null, true, $chunkSizeBytes ); $media->setFileSize(filesize($videoPath)); // Read the media file and upload it chunk by chunk. $status = false; $handle = fopen($videoPath, "rb"); while (!$status && !feof($handle)) { $chunk = fread($handle, $chunkSizeBytes); $status = $media->nextChunk($chunk); } fclose($handle); /** * Video has successfully been upload */ if ($status->status['uploadStatus'] == 'uploaded') { // Actions to perform for a successful upload // ...... } // If want to make other calls after the file upload, set setDefer back to false $client->setDefer(true); } else{ // @TODO Log error echo 'Problems creating the client'; } } catch(Google_Service_Exception $e) { print "Google_Service_Exception ".$e->getCode(). " message is ".$e->getMessage(); print "Stack trace is ".$e->getTraceAsString(); }catch (Exception $e) { print "Exception ".$e->getCode(). " message is ".$e->getMessage(); print "Stack trace is ".$e->getTraceAsString(); }
When the script runs, it raise this exception:
Exception 0 message is Failed to start the resume-able upload (HTTP 400: global, Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable)Stack trace is #0 D:\xampp\htdocs\youtube\src\Google\Http\MediaFileUpload.php(136): Google_Http_MediaFileUpload->getResumeUri() #1 D:\xampp\htdocs\youtube\resumable_upload.php(100): Google_Http_MediaFileUpload->nextChunk('\x00\x00\x00\x1Cftypf4v \x00\x00\x00...') #2 {main}
exception raise on
getResumeUri()
(line 281) inGoogle_Http_MediaFileUpload
, i have var dump the response from googleGoogle_Http_Request Object ( [batchHeaders:Google_Http_Request:private] => Array ( [Content-Type] => application/http [Content-Transfer-Encoding] => binary [MIME-Version] => 1.0 ) [queryParams:protected] => Array ( [part] => status,snippet [uploadType] => resumable ) [requestMethod:protected] => POST [requestHeaders:protected] => Array ( [content-type] => application/json; charset=UTF-8 [authorization] => Bearer XXXXXXXXXXXXXXXX [content-length] => 187 [x-upload-content-type] => video/* [x-upload-content-length] => 10201286 [expect] => ) [baseComponent:protected] => https://www.googleapis.com//upload [path:protected] => /youtube/v3/videos [postBody:protected] => {"snippet":{"categoryId":"22","description":"A video tutorial on how to upload to YouTube","tags":["youtube","tutorial"],"title":"A tutorial video"},"status":{"privacyStatus":"unlisted"}} [userAgent:protected] => [canGzip:protected] => [responseHttpCode:protected] => 400 [responseHeaders:protected] => Array ( [x-guploader-uploadid] => XXXXXXXXXXXXXXXXXXXXXXXXXX [location] => https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable [vary] => Origin X-Origin [content-type] => application/json; charset=UTF-8 [content-length] => 468 [date] => Fri, 10 Jul 2015 09:54:30 GMT [server] => UploadServer [alternate-protocol] => 443:quic,p=1 ) [responseBody:protected] => { "error": { "errors": [ { "domain": "global", "reason": "wrongUrlForUpload", "message": "Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable" } ], "code": 400, "message": "Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable" } } [expectedClass:protected] => Google_Service_YouTube_Video [expectedRaw:protected] => [accessKey] => )
What is wrong?Thanks for any help and sorry for bad English.
解决方案This seems to be a problem with PHP Client Library of Google API. Go to GOOGLE_LIB_PATH/Http/MediaFileUpload.php and replace this line:
$this->request->setBaseComponent($base . '/upload');
With this one:
$this->request->setBaseComponent($base . 'upload');
Try again and share the results. I faced a similar problem with Google Pubsub API where API path set by library was incorrect.
这篇关于PHP API Youtube上传,例外:无法启动可恢复的上传,上传必须发送到上传URL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!