YouTube API v3 - 直接上传到自己的频道

Posted

技术标签:

【中文标题】YouTube API v3 - 直接上传到自己的频道【英文标题】:YouTube API v3 - Direct upload to own channel 【发布时间】:2015-06-24 08:39:58 【问题描述】:

随着 YouTube v2 API 被弃用,我需要迁移到 v3。

在 v2 中,我使用同样已弃用的 ClientLogin (http://bit.ly/v2_ClientLogin_authentification) 身份验证方法进行身份验证,然后将用户视频上传到我的 YouTube 频道。

在 v3 中,我尝试使用 服务帐户 进行身份验证,使用的代码库与此处相同

php Youtube API v3 - Direct Upload - Unauthorized message

我从 API 端点收到相同的错误消息:

调用 POST https://www.googleapis.com/youtube/v3/videos?part=status%2Csnippet 时出错:(401) 未经授权

我还通过 Google 的 tokeninfo 进行了检查 (https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=[ACCESS_TOKEN]) 访问令牌有效:


 "issued_to": "***.apps.googleusercontent.com",
 "audience": "***.apps.googleusercontent.com",
 "scope": "https://www.googleapis.com/auth/youtube",
 "expires_in": 3592,
 "access_type": "offline"

我发现的所有 YouTube 示例均基于 OAuth2 和用户授权。 (就像这里的这个:http://bit.ly/yt-api-example-videoupload)。但这不是我想要的方式:用户不应该看到任何“请授权whatever.de 上传 YouTube 视频”并且视频应该上传到我的 YT 频道而不是他们的频道。

如果无法为此使用 API 服务帐户,您能否给我一个提示,如何使用 OAuth2 做到这一点? :-)

这是我当前的代码:

/** Config */ 
$private_key_password = 'notasecret';
$private_key_file = '***.p12';
$applicationName = '***';
$client_secret = '***'; // <--- WHERE IS THAT CLIENT_SECRET COMING FROM? Secret accounts do not have a client secret? 
$client_id = '***.apps.googleusercontent.com';
$service_mail = '***@developer.gserviceaccount.com';

$scope = 'https://www.googleapis.com/auth/youtube';
$url_youtube_token = 'https://accounts.google.com/o/oauth2/token';

$jwt = new Google_Auth_AssertionCredentials($service_mail, $scope, $private_key_file, $private_key_password, $url_youtube_token);
$jwt_assertion = $jwt->generateAssertion();

$data = array
(
    'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    'assertion' => $jwt_assertion,
);

$options = array
(
    'http' => array
    (
        'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        'method'  => 'POST',
        'content' => http_build_query($data),
    ),
);

$context = stream_context_create($options);
$result = file_get_contents($url_youtube_token, false, $context);

//var_dump($result); die();

try
    // Client init
    $client = new Google_Client();
    $client->setClientId($client_id);
    //$client->setClientSecret($client_secret); // <-- See above
    $client->setApplicationName($applicationName);

    $client->setAccessToken($result);

    if ($client->getAccessToken()) 
    
        if($client->isAccessTokenExpired()) 
        
            // @TODO Log error
            echo 'Access Token Expired!!<br/>'; // Debug
        

        $youtube = new Google_Service_Youtube($client);

        $videoPath = "./test.mp4";

        // Create a snipet with title, description, tags and category id
        $snippet = new Google_Service_YouTube_VideoSnippet();
        $snippet->setTitle("fmgonzalez test " . time());
        $snippet->setDescription("fmgonzalez test " . time() );
        $snippet->setTags(array("tag1", "tag2"));

        // Numeric video category. See
        // https://developers.google.com/youtube/v3/docs/videoCategories/list
        $snippet->setCategoryId("22");

        // Create a video status with privacy status. Options are "public", "private" and "unlisted".
        $status = new Google_Service_YouTube_VideoStatus();
        $status->privacyStatus = "public";

        // 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;

        // Create a MediaFileUpload with resumable uploads
        $insertRequest = $youtube->videos->insert("status,snippet", $video);

        $media = new Google_Http_MediaFileUpload
        (
            $client,
            $insertRequest,
            'video/*',
            null,
            true,
            $chunkSizeBytes
        );

        $media->setFileSize(filesize($videoPath));

        // Create a video insert request
        $insertResponse = $youtube->videos->insert("status,snippet", $video,
            array('mediaUpload' => $media));

        $uploadStatus = false;

        // Read file and upload chunk by chunk
        $handle = fopen($videoPath, "rb");
        $cont = 1;
        while (!$uploadStatus && !feof($handle)) 
        
            $chunk = fread($handle, $chunkSizeBytes);
            $uploadStatus = $media->nextChunk($insertResponse, $chunk);
            echo 'Chunk ' . $cont . ' uploaded <br/>';
            $cont++;
        

        fclose($handle);

        echo '<br/>OK<br/>';

    
    else
    
        // @TODO Log error
        echo 'Problems creating the client';
    

catch(Google_Service_Exception $e)

    print "Caught Google service Exception ".$e->getCode(). " message is <br>".$e->getMessage(). " <br>";
    //print "Stack trace is ".$e->getTraceAsString();

catch (Exception $e)

    echo $e->getMessage();

?>

【问题讨论】:

【参考方案1】:

无法使用服务帐户访问 YouTube API

Issue 5370: Youtube v3 Google Service Account Access

您需要使用Oauth2 您只需验证一次。使用离线访问保存您的刷新令牌。然后你可以用它来运行你的脚本。

$client->setAccessType('offline');   // Gets us our refreshtoken

【讨论】:

是否可以在没有用户凭据的情况下使用 OAuth2?我不需要请求用户权限,因为我不想将视频上传到用户的 YouTube 频道。如果可行,你有一个例子吗? 您必须在第一次进行身份验证时才能解决此问题。一旦您对其进行了身份验证,您就可以一遍又一遍地使用相同的刷新令牌来获取新的访问令牌。 YouTube 文档中都有 php 示例。 developers.google.com/youtube/v3/code_samples/php

以上是关于YouTube API v3 - 直接上传到自己的频道的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Rails API 中的 Attachinary 将图像从 React Native App 直接上传到 Cloudinary

不带 CORS 直接上传到 S3(非浏览器)

从浏览器错误请求直接上传到 Cloudinary

视频从应用上传到 youtube

视频从应用上传到youtube

使用 Youtube Data API V3 和 Google API Client PHP 将视频上传到 Youtube - 获取 401(未经授权)消息