Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
422 views
in Technique[技术] by (71.8m points)

java - CommentThreads: insert gives 403 Forbidden

I'm going nuts with this error. As far as I can see I've followed the instructions correctly. My scopes are YOUTUBE_FORCE_SSL. In desperation I've tried to add all Google Plus Scopes without luck. Still get the same error, both in the device, emulator and Google Api Explorer. The video I try to comment on are public. I have a Google+ profile and are signed in with it when I try to make a comment.

This is the full error:

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
    {
      "code" : 403,
      "errors" : [ {
        "domain" : "youtube.commentThread",
        "location" : "Authorization",
        "locationType" : "header",
        "message" : "The callers YouTube account is not connected to Google+.",
        "reason" : "ineligibleAccount"
      } ],
      "message" : "The callers YouTube account is not connected to Google+."
    }

This is my code:

try {
                    HashMap<String, String> parameters = new HashMap<>();
                    parameters.put("part", "snippet");


                    CommentThread commentThread = new CommentThread();
                    CommentThreadSnippet snippet = new CommentThreadSnippet();
                    Comment topLevelComment = new Comment();
                    CommentSnippet commentSnippet = new CommentSnippet();
                    commentSnippet.set("textOriginal", textComment);
                    commentSnippet.set("channelId", channelId);
                    commentSnippet.set("videoId", ytId);

                    topLevelComment.setSnippet(commentSnippet);
                    snippet.setTopLevelComment(topLevelComment);
                    commentThread.setSnippet(snippet);

                    YouTube.CommentThreads.Insert commentThreadsInsertRequest = mService.commentThreads().insert(parameters.get("part"), commentThread);

                    CommentThread response = commentThreadsInsertRequest.execute();
                    Log.i("COMMENT:", response.toString());
                }

Adding screenshot from Api Explorer:

enter image description here

Can you get CommentThreads: insert to work with the API Explorer? If so, how?

I have seen the answers to a similar question here and they don't solve this problem.

Any help is appreciated.

Edit 1

After further testing. Everything works fine with an old account I have. I've tried to see which settings could be different, so far without luck.

This also works if I switch to a YouTube brand account.

The problem remains, it don't work for all Google Accounts, not even when they're also Google+ accounts. The error seems to imply that the request is not made from a Google+ Account. Would be great if Google could clarify the exact reason.

Also, is it possible to programmatically make an account eligible to make a comment, after asking the permission from the account owner? How?

Edit 2

According to this page the reason for the error is this:

The YouTube account used to authorize the API request must be merged with the user's Google account to insert a comment or comment thread.

How can this be done within the app?

Edit 3

I guess the answer can be found here. You're not able to comment without a YouTube Channel.

The problem is that you're not able to comment unless you have a private YouTube Channel or are logged in with your Brand Account. Using the model to login that Google gave in the instructions don't allow login with Brand Accounts, they're not visible in the account picker.

The result is that you're able to login with an account that have YouTube Brand Accounts, but you will not be able to comment using that accountand since you're not able to pick a Brand Account there is no way to solve this unless you ask users to also create a private Channel. The error message should say something like this:

The callers YouTube account is not a YouTube Channel Account.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Since you can't post comments without a private YouTube Channel(see edits above) the solution would look something like this. If you can find a better one, please submit!

1) Catch the Error. Give Alert with instructions.

2) Launch a Webview with this URL: https://m.youtube.com/create_channel?chromeless=1&next=/channel_creation_done

3) Monitor the Webview and determine when the URL change to the following: https://m.youtube.com/channel_creation_done. The URL indicates that a channel has been created.

4) Close the Webview and resend the authorized API request.

The URLs above were found here but the error code to catch is not the same as on that page. You should catch a 403 with "reason" : "ineligibleAccount".

Update June 29th, 2018

I got back to this issue today and got it working in an acceptable way. See my implementation below:

1. Catch the error 403 after user posted comment without YouTube Channel

if(mLastError.getMessage().contains("403") && mLastError.getMessage().contains("ineligibleAccount")) {
                        // Show Alert with instruction
                        showAlertCreate("Please Create a YouTube Channel!", "You need a personal YouTube Channel linked to your Google Account before you can comment. Don't worry, it's easy to create one!

1) Tap on CREATE below and wait for page to load.

2) Login if needed.

3) Tap CREATE CHANNEL and wait until comment is posted.");
}

Code for Alert:

public void showAlertCreate(String title, String description) {
    AlertDialog.Builder builder;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        builder = new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert);
    } else {
        builder = new AlertDialog.Builder(this);
    }
    builder.setTitle(title)
            .setMessage(description)
            .setPositiveButton(R.string.yes_create, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // Start Youtube WebView to create Channel
                    Intent intent = new Intent(mContext, WebViewActivity.class);
                    startActivityForResult(intent, 777);
                }
            })
            .setIcon(android.R.drawable.ic_dialog_alert)
            .show();
}

2. When user tap CREATE in Alert, open this WebView

Notice this code to start Intent in alert above:

// Start Youtube WebView to create Channel
                    Intent intent = new Intent(mContext, WebViewActivity.class);
                    startActivityForResult(intent, 777);

XML for WebView:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".WebViewActivity">

    <WebView
        android:id="@+id/create_channel"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

Code for WebView:

public class WebViewActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_view);

        WebView createChannel = findViewById(R.id.create_channel);

        createChannel.setWebViewClient(new WebViewClient() {
            public void onPageFinished(WebView view, String url) {
                if (url!=null && url.contains("https://m.youtube.com/channel_creation_done")) {
                    view.setVisibility(View.INVISIBLE);
                    //Log.i("URLWEB", url);
                    Intent intent = new Intent();
                    intent.putExtra("created", "yes");
                    setResult(RESULT_OK, intent);
                    finish();
                }
            }
        });

        createChannel.loadUrl("https://m.youtube.com/create_channel?chromeless=1&next=/channel_creation_done");

    }
}

3. Catch when user completed Create Channel step in your activity

In onActivityResult() include something like this:

if (requestCode == 777) {
    if(resultCode == RESULT_OK) {
        // Receive intent from WebView, if new Channel, repost comment/reply
        String created = data.getStringExtra("created");
        if(created.equals("yes")) {
            // Posting the comment again
            getResultsFromApi();
        }
    }
}

Not the cleanest solution but it works.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...