指定使用PHP在Youtube API中上载视频的频道

指定使用PHP在Youtube API中上载视频的频道,php,youtube-api,youtube-data-api,Php,Youtube Api,Youtube Data Api,我的谷歌账户下有两个频道。我可以使用Youtube API for PHP将视频上传到我的主频道。我想把视频上传到我的第二个频道(不是主频道)。我搜索了很多,但找不到解决方案。我刚才想的是,我可能需要使用Google\u服务\u YouTube\u ChannelContentOwnerDetails()类,但我不知道如何将此详细信息指定给$YouTube->videos->insert(“状态,片段”,$video)在指定的方法。我还发现,我可能需要使用OnBehalfOfContentTow

我的谷歌账户下有两个频道。我可以使用Youtube API for PHP将视频上传到我的主频道。我想把视频上传到我的第二个频道(不是主频道)。我搜索了很多,但找不到解决方案。我刚才想的是,我可能需要使用
Google\u服务\u YouTube\u ChannelContentOwnerDetails()
类,但我不知道如何将此详细信息指定给
$YouTube->videos->insert(“状态,片段”,$video)
在指定的方法。

我还发现,我可能需要使用
OnBehalfOfContentTowner
OnBehalfOfContentTowner频道
属性,但我认为这些参数适用于那些有权访问其他频道以代表他们管理频道的帐户,我不需要使用它们,因为我在一个谷歌账户下拥有两个频道。(也许我错了)

我只想通过我的主频道授权将视频上传到我的第二个帐户。

在这方面的任何帮助都将不胜感激。

无法为API端点指定频道ID。但请容忍我一段时间

第一次发布时,他/她的应用程序将接收以下JSON对象:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/youtube.force-ssl",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}
访问令牌是短期的,而刷新令牌是长期的(但可以撤销)。这种JSON对象缓存在本地文件中,以便在应用程序需要新的访问令牌(基于存储的刷新令牌)时使用。需要将访问令牌传递给每个需要授权的API端点

上述两个令牌与授权过程中登录的Google帐户相关。在大多数情况下,每个谷歌账户都与某个YouTube账户(即频道)唯一关联。但也可能有与多个YouTube频道相关联的谷歌账户(请参阅“使用谷歌账户管理的品牌账户”一节)

现在我的猜测是:
N
这样的JSON对象(相对于相同的范围;例如
https://www.googleapis.com/auth/youtube.upload
),每一个都与一个不同的Youtube频道关联——都在一个谷歌账户的保护伞下——,所有标记都本地存储在单独的文件中(甚至全部存储在一个文件中),这样,当发出需要以给定通道为目标的API调用时,就可以从整个
N
对象集中以编程方式选择关联的标记对


我答案的第二部分包含了说明我上述猜想的源代码。我不打算在这里介绍一个完整和/或包罗万象的解决方案,而只是提出一个应用程序框架,以适应具体PHP应用程序的各种运行方式(例如,单个桌面应用程序或在未安装浏览器的远程服务器上自主运行的应用程序)

该应用程序管理一组JSON文件——所有文件都存储在同一目录中(
$auth\u conf\u path
)。每个文件都包含与特定频道相关的必需凭据,以便能够从中创建类
Google\u Client
的适当实例。这些JSON文件的名称的格式为
CHANNEL\u ID.JSON
,其中
CHANNEL\u ID
是该文件所引用的频道的ID

该应用程序分为两部分:一部分在启动OAuth授权流时创建这些凭证JSON文件;另一种方法是相对于已存在凭证JSON文件的给定通道进行API调用

应用程序的第一部分,通过在通常的PHP OAuth流中使用
initChannelCredentials
,生成与应用程序被授予访问权限的YouTube频道相关的凭据ID和JSON文件

应用程序的第二部分,在从
makeChannelClient
获取
Google_Client
类的实例后,针对传递给该函数的ID标识的通道进行实际的API端点调用

function initChannelCredentials(
  $auth_conf_path, $scopes, $redirect_uri, $client_code)
{
  if (!is_dir($auth_conf_path))
    throw new InvalidArgumentException(sprintf(
      'Auth config path "%s" does not exist', $auth_conf_path));

  $client = new Google_Client();
  $client->setAuthConfigFile(
    $auth_conf_path . DIRECTORY_SEPARATOR . 'client_secrets.json');
  $client->setRedirectUri($redirect_uri);
  $client->setScopes($scopes);

  $cred = $client->fetchAccessTokenWithAuthCode($client_code);

  $youtube = new Google_Service_YouTube($client);
  $response = $youtube->channels->listChannels('id', array(
    'mine' => 'true'
  ));

  $channel_id = $response[0]['id'];
  $cred_file = $auth_conf_path . DIRECTORY_SEPARATOR . $channel_id . '.json';
  if (file_exists($cred_file))
    throw new InvalidArgumentException(sprintf(
      'Credentials file for channel "%s" already exists', $channel_id));

  file_put_contents($cred_file, json_encode($cred));

  return $channel_id;
}
请注意,如上所述的应用程序比原始帖子和我上面的推测中包含的应用程序更一般。应用程序管理的JSON文件(同样是YouTube频道)不需要在一个Google帐户的保护下工作(正如我猜想的那样)。这些通道很可能与不同的Google帐户相关,只要这种PHP应用程序的具体体现能够正确处理多个Google帐户。

我尝试在snippet对象中设置'--channelId',但这似乎不起作用。
解决方案是为不同的子通道生成不同的oauth2.json。

感谢您的详细回复。你能给出一个通过主通道授权获得N个JSON对象的例子吗?是的,这将在我的回答的下一部分给出,我将在稍后阐述。据我所知,无论实现语言(PHP、Python、Java等)如何,目前还没有解决这个问题的公共代码示例。我还需要你继续关注和帮助,因为你已经有一个与两个YouTube频道相关联的Google帐户。请仔细阅读。OP说,在OAuth流程中,他会看到一个屏幕,让他在两个YouTube频道之间进行选择(在他选择了一个Google帐户之后,因此已经通过了某个Google帐户的身份验证)。我需要你确认你也看到了这样一个屏幕,允许你从两个相关的YouTube频道中选择一个——这发生在你登录谷歌帐户之后。是的,我看到了两个YouTube频道,我从列表中选择了主频道。这是一个非常好的消息!现在,我想让你测试一下下面的
function makeChannelClient($auth_conf_path, $channel_id)
{
  if (!is_dir($auth_conf_path))
    throw new InvalidArgumentException(sprintf(
      'Auth config path "%s" does not exist', $auth_conf_path));

  $cred_file = $auth_conf_path . DIRECTORY_SEPARATOR . $channel_id . '.json';
  if (!file_exists($cred_file))
    throw new InvalidArgumentException(sprintf(
      'Credentials file for channel "%s" does not exist', $channel_id));

  if (!$cred = json_decode(file_get_contents($cred_file), true))
    throw new LogicException(sprintf(
      'Invalid content of credentials file for channel "%s"', $channel_id));

  $client = new Google_Client();
  $client->setAccessType('offline');
  $client->setScopes($cred['scope']);
  $client->setAccessToken($cred);

  if ($client->isAccessTokenExpired()) {
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
    file_put_contents($cred_file, json_encode($client->getAccessToken()));
  }

  return $client;
}