无法为Videos.insert API 端点指定通道 ID。不过还是忍一忍吧……
第一次发出 the OAuth 2.0 authorization flow 时,他/她的应用接收到以下 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"
}
访问令牌是短暂的,而刷新令牌是长期存在的(但可以撤销at will)。这种 JSON 对象被缓存在本地文件中,以便以后在应用程序需要新的访问令牌(基于存储的刷新令牌的 is obtained from the API)时使用。访问令牌需要传递到每个需要授权的 API 端点。
以上两个令牌是相对于一个在授权过程中登录的谷歌帐户而言的。在最常见的情况下,每个 Google 帐户都与某个 YouTube 帐户(即频道)唯一关联。但是可能会有与多个 YouTube 频道相关联的 Google 帐户(请参阅this doc,使用由您的 Google 帐户管理的品牌帐户部分)。
现在我的猜想:我确实认为有可能拥有N 这样的 JSON 对象(相对于同一范围;例如 https://www.googleapis.com/auth/youtube.upload),每个对象都与不同的 Youtube 相关联频道 - 都在一个 Google 帐户的保护伞下 - 所有都存储在本地单独的文件中(甚至都存储在一个文件中),这样,在发出需要针对给定频道的 API 调用时,以编程方式选择整组N 对象中的相关标记对。
我的答案的第二部分包含说明我上面猜想的源代码。我不打算在这里展示一个完整的和/或包罗万象的解决方案,而只是提出一个应用程序框架,以适应具体 PHP 应用程序可能运行的各种方式(例如,单个桌面应用程序或在远程自动运行的应用程序) 没有安装浏览器的服务器)。
该应用管理一组 JSON 文件——所有文件都存储在同一目录 ($auth_conf_path) 中。每个文件都包含与某个通道相关的所需凭据,以便能够从中创建一个适当的类Google_Client 的实例。这些 JSON 文件的名称格式为 CHANNEL_ID.json,其中 CHANNEL_ID 是该文件所引用的频道的 ID。
应用分为两部分:一是在启动 OAuth 授权流程时创建这些凭证 JSON 文件;二是在启动 OAuth 授权流程时创建这些凭证 JSON 文件;另一个相对于给定通道进行 API 调用(凭据 JSON 文件已存在)。
应用程序的第一部分,通过在通常的 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;
}
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;
}
请注意,上述应用程序比包含在原始帖子和我上面的猜想中的应用程序更通用。由应用程序管理的凭据 JSON 文件(同样是 YouTube 频道)不需要在单个 Google 帐户的保护下全部工作(正如我的猜想所规定的那样)。这些渠道很可能与不同的 Google 帐户相关,只要此类 PHP 应用程序的具体化身能够正确处理多个 Google 帐户即可。