【发布时间】:2018-02-26 16:26:45
【问题描述】:
我们有一个基于移动设备的视频编辑器,可以将人们的视频和缩略图上传到 AWS S3 存储桶。然后,这会启动一个 AWS SWF 进程来编码、上传视频、上传缩略图并等待所述视频的处理,然后再告诉用户他们的视频已完成。每个用户都使用自己的访问令牌,以便将视频上传到自己的 YouTube 频道。
这在过去 12 个月左右一直很好,从 YouTube 端上传缩略图时偶尔会抛出 backendError,我们有一个重试策略,将等待 1、3、8、15 等秒。到第二次或第三次重试时,YouTube 服务器已自行解决,一切都恢复正常。
截至 2017 年 9 月 17 日 17:29(澳大利亚东部标准时间),我们的所有视频都没有成功上传缩略图。系统抛出 Google_Service_Exception,状态码为 503,响应正文为,
{“错误”:{“错误”:[{ “域”:“全球”, “原因”:“后端错误”, “消息”:“后端错误”}],“代码”:503,“消息”:“后端错误”} }
此时,没有更新任何服务器包,也没有更新我们自己的代码或使用的作曲家包。
我尝试撤销我的访问令牌,在另一个帐户上生成了我自己的一个新项目和新的 API 密钥/秘密,但在我们的测试服务器上仍然得到相同的错误处理缩略图(应该排除速率限制,我们还很远低于任何限制)。
视频上传仍然可以正常工作。从我们的系统编辑视频标题仍然可以正常工作(意味着访问令牌是有效的,并且如果频道允许,则需要设置缩略图的范围)。手动将缩略图直接上传到 YouTube 仍然可以正常工作(排除频道本身有问题)。
我什至重新下载了sample code 并创建了一个新测试,但它仍然失败。它在所有情况下都失败的具体行是
$status = $media->nextChunk($chunk);
我不知道是什么导致了这个突然的问题,如果我们没有改变,所有的图像都是 1920x1080 jpg 远低于 2mb,完全不同的项目和访问令牌,全新的示例代码。而且我假设如果每个使用 YouTube 数据 API 的人在过去 24 小时内都遇到此错误,将会有更多关于它的帖子。所以不确定我们还能尝试什么。
有什么建议吗?
编辑: 嗯……这很奇怪。我设法通过命令行从我们的服务器使用 cURL 上传。
curl -X POST -F "image=@thumbnail_test.jpg" "https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=dCdQ2tJ5wIs&key={REMOVED}&access_token={REMOVED}"
而且效果很好。这样就排除了我们的服务器问题(IP 被阻止或其他问题),我们的访问令牌问题或我们的 client_id 密钥问题。它还以某种方式排除了 YouTube 后端的不良行为(假设 cURL 和 php 通过相同的机制连接)。
剩下的就是,我们将缩略图上传到 YouTube(并且只有缩略图)现在通过 PHP 失败,没有服务器或服务器代码更改,但在命令行中通过 cURL 使用相同的访问令牌和密钥可以正常工作。
编辑 2: 我已经上传了一个示例here on github(包括一个示例图像和 composer.json 文件)。它在 1 中有 2 个示例。显示脚本因 youtube php sdk 失败,但随后使用相同凭据成功处理 curl 请求。脚本不包括获取访问或刷新令牌。
主要的test.php脚本如下。
<?php
define('GOOGLE_CLIENT_ID', 'REPLACE_ME');
define('GOOGLE_CLIENT_SECRET', 'REPLACE_ME');
require_once 'vendor/autoload.php';
$token = [
'access_token' => 'REPLACE_ME',
'refresh_token' => 'REPLACE_ME',
'token_type' => 'Bearer',
'expires_in' => '3600',
'created' => REPLACE_ME
];
$youtube_id = 'REPLACE_ME';
$thumbnail_path = realpath('thumbnail.jpg');
/*
// Doing the exact same request in cURL works fine.
$data = [
'filedata' => new CURLFile($thumbnail_path, 'image/jpeg', basename($thumbnail_path)),
];
// Execute remote upload
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, [
'Authorization: Bearer '.$token['access_token'],
]);
curl_setopt($curl, CURLOPT_URL, 'https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId='.$youtube_id.'&key='.GOOGLE_CLIENT_SECRET);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_VERBOSE, 1);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
*/
// Based on php sample from https://developers.google.com/youtube/v3/docs/thumbnails/set
$client = new Google_Client();
$client->setClientId(GOOGLE_CLIENT_ID);
$client->setClientSecret(GOOGLE_CLIENT_SECRET);
$client->setScopes([
'https://www.googleapis.com/auth/yt-analytics.readonly',
'https://www.googleapis.com/auth/youtube',
'https://www.googleapis.com/auth/youtube.upload',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
]);
$client->setAccessType('offline');
// If you want to use a refresh token instead to get an access token from it.
//$token = $client->fetchAccessTokenWithRefreshToken($refresh_token);
//var_dump($token);
$client->setAccessToken($token);
$service = new Google_Service_YouTube($client);
try
{
// Specify the size of each chunk of data, in bytes. Set a higher value for
// reliable connection as fewer chunks lead to faster uploads. Set a lower
// value for better recovery on less reliable connections.
$chunkSizeBytes = 1 * 1024 * 1024;
// Create a MediaFileUpload object for resumable uploads.
// Parameters to MediaFileUpload are:
// client, request, mimeType, data, resumable, chunksize.
$client->setDefer(true);
$request = $service->thumbnails->set($youtube_id);
$client->setDefer(false);
$mimeType = 'image/jpeg';
$media = new Google_Http_MediaFileUpload(
$client,
$request,
$mimeType,
null,
true,
$chunkSizeBytes
);
$filesize = filesize($thumbnail_path);
echo "Filesize: $filesize\n";
$media->setFileSize($filesize);
// Read the media file and upload it chunk by chunk.
$status = false;
$handle = fopen($thumbnail_path, "rb");
while (!$status && !feof($handle))
{
$chunk = fread($handle, $chunkSizeBytes);
$status = $media->nextChunk($chunk); // The line where the Google_Service_Exception exception is thrown.
}
fclose($handle);
echo "Thumbnail uploaded success\n";
}
catch (Google_Service_Exception $err)
{
echo $err->getMessage();
}
catch (Exception $err)
{
echo $err->getMessage();
}
【问题讨论】:
-
寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。请参阅:如何创建最小、完整和可验证的示例。
-
您能否为我链接到最小、完整和可验证的示例,以便我可以为其他读者更新问题的最佳实践?
-
stackoverflow.com/help/mcve 你不应该包括你的客户 ID 和我自己的秘密。
标签: php youtube-api thumbnails youtube-data-api