Youtube实时流API给出livePermissionBlocked错误

问题描述

我正在尝试使用服务帐户委派设置youtube实时流API。我已经完成了在域上委派服务帐户的所有必要步骤。 我有一个用户拥有的YouTube频道,其电子邮件ID为该域名。频道拥有超过1万名订阅者,并且拥有直播视频的所有必要权限(我可以通过youtube studio直播)。 使用youtube Java API时,出现此错误

{
  "code" : 403,"errors" : [ {
    "domain" : "youtube.livebroadcast","message" : "The user is blocked from live streaming.","reason" : "livePermissionBlocked","extendedHelp" : "https://support.google.com/youtube/answer/2853834"
  } ],"message" : "The user is blocked from live streaming."
}

我附上我的代码以供参考

    private static final Collection<String> ScopES =
            Arrays.asList("https://www.googleapis.com/auth/youtube.force-ssl");
    private static final String APPLICATION_NAME = "youtubeLive";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

    /**
     * Create an authorized Credential object.
     *
     * @return an authorized Credential object.
     * @throws IOException
     */
    public static Credential authorize(final NetHttpTransport httpTransport) throws IOException,GeneralSecurityException {
        // Load client secrets.
        InputStream in = new FileInputStream(CLIENT_SECRETS);
//        GoogleClientSecrets clientSecrets =
//                GoogleClientSecrets.load(JSON_FACTORY,new InputStreamReader(in));
//        // Build flow and trigger user authorization request.
//        GoogleAuthorizationCodeFlow flow =
//                new GoogleAuthorizationCodeFlow.Builder(httpTransport,JSON_FACTORY,clientSecrets,ScopES)
//                        .build();
//        Credential credential = new AuthorizationCodeInstalledApp(flow,null).authorize("user");
//        GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(CLIENT_SECRETS))
//                .createScoped(ScopES);
        GoogleCredential credential = new GoogleCredential.Builder()
                .setServiceAccountScopes(ScopES)
                .setServiceAccountPrivateKeyFromP12File(new File("/Users/ashishjindal/Downloads/youtubelive-291213-be89f6b31144.p12"))
                .setServiceAccountId("a******@youtubelive****.iam.gserviceaccount.com")
                .setServiceAccountUser("USER@MY_DOMAIN.COM")
                .setJsonFactory(JSON_FACTORY)
                .setTransport(httpTransport)
                .build();
        return credential;
    }

    /**
     * Build and return an authorized API client service.
     *
     * @return an authorized API client service
     * @throws GeneralSecurityException,IOException
     */
    public static YouTube getService() throws GeneralSecurityException,IOException {
        final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        Credential credential = authorize(httpTransport);
        return new YouTube.Builder(httpTransport,credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }



    @Scheduled(fixedDelay = 1000l)
    public void test() throws IOException,GeneralSecurityException {
        YouTube youtubeService = getService();
        Livebroadcast livebroadcast = new Livebroadcast();

        // Add the contentDetails object property to the Livebroadcast object.
        LivebroadcastContentDetails contentDetails = new LivebroadcastContentDetails();

        contentDetails.setEnableClosedCaptions(true);
        contentDetails.setEnableContentEncryption(true);
        contentDetails.setEnableDvr(true);
        contentDetails.setEnableEmbed(true);
        contentDetails.setEnableAutoStart(true);
        contentDetails.setRecordFromStart(true);
        contentDetails.setStartWithSlate(true);
        livebroadcast.setContentDetails(contentDetails);

        LivebroadcastSnippet snippet = new LivebroadcastSnippet();
        snippet.setScheduledEndTime(new DateTime("2030-10-10T00:00:00"));
        snippet.setScheduledStartTime(new DateTime("2029-10-10T00:00:00"));
        snippet.setTitle("Test broadcast");
        snippet.setChannelId("CHANNEL ID OWNED BY MY USER");
        livebroadcast.setSnippet(snippet);

        LivebroadcastStatus status = new LivebroadcastStatus();
        status.setPrivacyStatus("unlisted");
        livebroadcast.setStatus(status);

        YouTube.Livebroadcasts.Insert request = youtubeService.livebroadcasts()
                .insert("snippet,contentDetails,status",livebroadcast);
        livebroadcast = request.execute();
        System.out.println(response);
     }

编辑:我已经确定了根本原因。我正在传递属于该用户进一步拥有的品牌帐户的频道ID。一个用户可以在youtube上拥有多个品牌帐户。现在,我的新问题是如何使用服务帐户模拟品牌帐户。 我发现了一些有用的线程:

YouTube API and brand account

Using Youtube Data API to Edit with Brand Account Playlist

解决方法

YouTube API不支持服务帐户(就像其他Google API一样)。

这里引用了官方API文档Move from ClientLogin to OAuth 2.0Service Accounts do not work with the YouTube API部分(以下为我的重点):

服务帐户不适用于YouTube数据API调用,因为服务帐户需要关联的YouTube频道,并且您无法将新频道或现有频道与服务帐户相关联。如果您使用服务帐户调用YouTube数据API,则API服务器returns an error的错误类型设置为unauthorized,原因设置为youtubeSignupRequired

此外,这是从official docs的另一个地方提取的文本,再次说明了这一事实(以下重点也是我的意思):

如果您尝试使用OAuth 2.0服务帐户流,通常会看到此错误。 YouTube不支持服务帐户,如果您尝试使用服务帐户进行身份验证,则会收到此错误。

我从上面提取官方声明的上下文不包含在您上面的显示中。尽管如此,事实仍然存在。

这一次来自Live Streaming API docs本身的另一句话断言了上述事实(下面的重点也是我的):

服务帐户流支持不访问用户信息的服务器到服务器的交互。但是, YouTube Live Streaming API不支持此流程。由于无法将服务帐户链接到YouTube帐户,因此尝试使用此流程授权请求将产生NoLinkedYouTubeAccount错误。

因此,您必须确认您无法通过服务帐户使用YouTube的相应API发起直播。