Python Youtube API commentThreads.update在回复topLevelComment时返回400错误

Python Youtube API commentThreads.update在回复topLevelComment时返回400错误,python,youtube-api,hootsuite,Python,Youtube Api,Hootsuite,报告Youtube Api commentThreads.update上可能存在的错误 受影响的API名称:CommentThreads:更新 问题摘要:CommentThreads:update调用此api以更新CommentThreads.list返回的topLevelComment时,我遇到了一个400错误。我在一个内部工具中使用这个API,以允许我回复评论。在过去的几个月里,它运转良好。。。在过去的几天里(~2016-11-07),我的代码没有任何变化,API开始返回400错误。我的所有

报告Youtube Api commentThreads.update上可能存在的错误

受影响的API名称:CommentThreads:更新

问题摘要:CommentThreads:update调用此api以更新CommentThreads.list返回的topLevelComment时,我遇到了一个400错误。我在一个内部工具中使用这个API,以允许我回复评论。在过去的几个月里,它运转良好。。。在过去的几天里(~2016-11-07),我的代码没有任何变化,API开始返回400错误。我的所有内部评论系统现在都停止了,因为我不知道如何解决这个问题。我尝试和测试的每一件事都会带来400错误和下面的信息

虽然这可能是暂时性错误,但它通常表示请求输入无效

即使使用API控制台,我也会犯同样的错误! 我打赌?这是一个暂时的错误,我希望谷歌能够修复

复制问题的步骤:

  • 使用CommentThreads.list检索“heldForReview”线程
  • 尝试更新返回的topLevelComment更改[“topLevelComment”][“snippet”][“textOriginal”]=“some text”。或者,将“moderationStatus”更改为“published”。错误是一样的
  • 使用Python API示例,特别是来自的comment_threads.py文件,可以很容易地发现这种行为
  • 预期输出:线程的顶级注释应该是可见的(在将moderationStatus设置为published之后),并将“some text”作为第一个子注释作为其答案

    实际结果:

        {
     "error": {
      "errors": [
       {
        "domain": "youtube.commentThread",
        "reason": "processingFailure",
        "message": "The API server failed to successfully process the request. While this can be a transient error, it usually indicates that the requests input is invalid. Check the structure of the \u003ccode\u003ecommentThread\u003c/code\u003e resource in the request body to ensure that it is valid.",
        "locationType": "other",
        "location": "body"
       }
      ],
      "code": 400,
      "message": "The API server failed to successfully process the request. While this can be a transient error, it usually indicates that the requests input is invalid. Check the structure of the \u003ccode\u003ecommentThread\u003c/code\u003e resource in the request body to ensure that it is valid."
     }
    }
    
    注意:我在下面提供了一个示例代码。

    #/usr/bin/python
    #用法示例:
    #python comment_threads.py--channelid=''--videoid=''--text=''
    导入httplib2
    导入操作系统
    导入系统
    从apiclient.discovery从文档导入生成
    从apiclient.errors导入HttpError
    从oauth2client.client导入流\u从\u clientsecrets
    从oauth2client.file导入存储
    从oauth2client.tools导入argparser,运行\u流
    #CLIENT\u SECRETS\u FILE变量指定包含
    #此应用程序的OAuth 2.0信息,包括其客户端id和
    #客户的秘密。您可以从中获取OAuth 2.0客户端ID和客户端机密
    #{{googlecloudconsole}}位于
    # {{ https://cloud.google.com/console }}.
    #请确保已为项目启用YouTube数据API。
    #有关使用OAuth2访问YouTube数据API的更多信息,请参阅:
    #   https://developers.google.com/youtube/v3/guides/authentication
    #有关client_secrets.json文件格式的更多信息,请参阅:
    #   https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
    CLIENT\u SECRETS\u FILE=“CLIENT\u SECRETS.json”
    #此OAuth 2.0访问范围允许对
    #已验证用户的帐户,并要求请求使用SSL连接。
    YOUTUBE\u读取\u写入\u SSL\u范围=”https://www.googleapis.com/auth/youtube.force-ssl"
    YOUTUBE\u API\u服务\u NAME=“YOUTUBE”
    YOUTUBE\u API\u VERSION=“v3”
    #此变量定义了一条消息,如果客户端\u SECRETS\u文件
    #失踪。
    缺少客户机密消息“”
    警告:请配置OAuth 2.0
    要运行此示例,您需要填充client_secrets.json文件
    网址:
    %
    使用来自API控制台的信息
    https://console.developers.google.com
    有关client_secrets.json文件格式的更多信息,请访问:
    https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
    “”“%os.path.abspath(os.path.join(os.path.dirname(\u_文件\u_),CLIENT\u SECRETS\u文件))
    #授权请求并存储授权凭据。
    def get_authenticated_服务(args):
    flow=flow\u from\u clientsecrets(客户端秘密文件,作用域=YOUTUBE\u读写\u SSL\u作用域,消息=缺少客户端秘密\u消息)
    存储=存储(“%s-oauth2.json”%sys.argv[0])
    凭据=存储。获取()
    如果凭据为无或凭据无效:
    凭据=运行\u流(流、存储、参数)
    #受信任的测试人员可以从开发者页面下载此发现文档
    #它应该和代码在同一个目录中。
    将open(“youtube-v3-discoverydocument.json”、“r”)作为f:
    doc=f.read()
    从\u文档(doc,http=credentials.authorize(httplib2.http())返回生成\u
    #调用API的commentThreads.list方法以列出现有注释。
    def获取评论(youtube、视频id、频道id):
    结果=youtube.commentThreads().list(
    part=“snippet”,
    videoId=视频\u id,
    channelId=通道id,
    #仅筛选保留供审阅的注释
    #这些评论只有一个顶级评论
    moderationStatus=“heldForReview”,
    textFormat=“plainText”).execute()
    对于结果中的项目[“项目”]:
    注释=项目[“代码段”][“topLevelComment”]
    author=comment[“snippet”][“authorDisplayName”]
    text=注释[“代码段”][“文本显示”]
    打印“评论人%s:%s%”(作者,文本)
    返回结果[“项目”]
    #调用API的commentThreads.insert方法以插入注释。
    def插入注释(youtube、频道id、视频id、文本):
    insert_result=youtube.commentThreads().insert(
    part=“snippet”,
    身体=口述(
    snippet=dict(
    channelId=通道id,
    videoId=视频\u id,
    topLevelComment=dict(
    snippet=dict(
    text原始=文本
    )
    )
    )
    )
    ).execute()
    comment=insert_result[“snippet”][“topLevelComment”]
    author=comment[“snippet”][“authorDisplayName”]
    text=注释[“代码段”][“文本显示”]
    打印“为%s:%s插入的注释”%(作者,文本)
    #调用API的commentThreads.update方法来更新现有注释。
    def更新_评论(youtube,评论):
    注释[“snippet”][“topLevelComment”][“snippet”][“textOriginal”]=“已更新”
    update_result=youtube.commentThreads().update(
    part=“snippet”,
    body=注释
    ).execute()
    注释=更新
    
    #!/usr/bin/python
    # Usage example:
    # python comment_threads.py --channelid='<channel_id>' --videoid='<video_id>' --text='<text>'
    import httplib2
    import os
    import sys
    
    from apiclient.discovery import build_from_document
    from apiclient.errors import HttpError
    from oauth2client.client import flow_from_clientsecrets
    from oauth2client.file import Storage
    from oauth2client.tools import argparser, run_flow
    
    # The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
    
    # the OAuth 2.0 information for this application, including its client_id and
    # client_secret. You can acquire an OAuth 2.0 client ID and client secret from
    # the {{ Google Cloud Console }} at
    # {{ https://cloud.google.com/console }}.
    # Please ensure that you have enabled the YouTube Data API for your project.
    # For more information about using OAuth2 to access the YouTube Data API, see:
    #   https://developers.google.com/youtube/v3/guides/authentication
    # For more information about the client_secrets.json file format, see:
    #   https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
    CLIENT_SECRETS_FILE = "client_secrets.json"
    
    # This OAuth 2.0 access scope allows for full read/write access to the
    # authenticated user's account and requires requests to use an SSL connection.
    YOUTUBE_READ_WRITE_SSL_SCOPE = "https://www.googleapis.com/auth/youtube.force-ssl"
    YOUTUBE_API_SERVICE_NAME = "youtube"
    YOUTUBE_API_VERSION = "v3"
    
    # This variable defines a message to display if the CLIENT_SECRETS_FILE is
    # missing.
    MISSING_CLIENT_SECRETS_MESSAGE = """
    WARNING: Please configure OAuth 2.0
    
    To make this sample run you will need to populate the client_secrets.json file
    found at:
       %s
    with information from the APIs Console
    https://console.developers.google.com
    
    For more information about the client_secrets.json file format, please visit:
    https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
    """ % os.path.abspath(os.path.join(os.path.dirname(__file__),CLIENT_SECRETS_FILE))
    
    # Authorize the request and store authorization credentials.
    def get_authenticated_service(args):
      flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_READ_WRITE_SSL_SCOPE,message=MISSING_CLIENT_SECRETS_MESSAGE)
    
      storage = Storage("%s-oauth2.json" % sys.argv[0])
      credentials = storage.get()
    
      if credentials is None or credentials.invalid:
        credentials = run_flow(flow, storage, args)
    
      # Trusted testers can download this discovery document from the developers page
      # and it should be in the same directory with the code.
      with open("youtube-v3-discoverydocument.json", "r") as f:
        doc = f.read()
        return build_from_document(doc, http=credentials.authorize(httplib2.Http()))
    
    
    # Call the API's commentThreads.list method to list the existing comments.
    def get_comments(youtube, video_id, channel_id):
      results = youtube.commentThreads().list(
        part="snippet",
        videoId=video_id,
        channelId=channel_id,
        # ONLY FILTER COMMENTS THAT ARE HELD FOR REVIEW
        # THOSE COMMENTS ONLY HAVE ONE TOP LEVEL COMMENT
        moderationStatus="heldForReview",
        textFormat="plainText").execute()
    
      for item in results["items"]:
        comment = item["snippet"]["topLevelComment"]
        author = comment["snippet"]["authorDisplayName"]
        text = comment["snippet"]["textDisplay"]
        print "Comment by %s: %s" % (author, text)
    
      return results["items"]
    
    
    # Call the API's commentThreads.insert method to insert a comment.
    def insert_comment(youtube, channel_id, video_id, text):
      insert_result = youtube.commentThreads().insert(
        part="snippet",
        body=dict(
          snippet=dict(
            channelId=channel_id,
            videoId=video_id,
            topLevelComment=dict(
              snippet=dict(
                textOriginal=text
              )
            )
          )
        )
      ).execute()
    
      comment = insert_result["snippet"]["topLevelComment"]
      author = comment["snippet"]["authorDisplayName"]
      text = comment["snippet"]["textDisplay"]
      print "Inserted comment for %s: %s" % (author, text)
    
    
    # Call the API's commentThreads.update method to update an existing comment.
    def update_comment(youtube, comment):
      comment["snippet"]["topLevelComment"]["snippet"]["textOriginal"] = 'updated'
      update_result = youtube.commentThreads().update(
        part="snippet",    
        body=comment
      ).execute()
    
      comment = update_result["snippet"]["topLevelComment"]
      author = comment["snippet"]["authorDisplayName"]
      text = comment["snippet"]["textDisplay"]
      print "Updated comment for %s: %s" % (author, text)
    
    
    if __name__ == "__main__":
      # The "channelid" option specifies the YouTube channel ID that uniquely
      # identifies the channel for which the comment will be inserted.
      argparser.add_argument("--channelid",
        help="Required; ID for channel for which the comment will be inserted.")
      # The "videoid" option specifies the YouTube video ID that uniquely
      # identifies the video for which the comment will be inserted.
      argparser.add_argument("--videoid",
        help="Required; ID for video for which the comment will be inserted.")
      # The "text" option specifies the text that will be used as comment.
      argparser.add_argument("--text", help="Required; text that will be used as comment.")
      args = argparser.parse_args()
    
      if not args.channelid:
        exit("Please specify channelid using the --channelid= parameter.")
      if not args.videoid:
        exit("Please specify videoid using the --videoid= parameter.")
      if not args.text:
        exit("Please specify text using the --text= parameter.")
    
      youtube = get_authenticated_service(args)
      try:
        # All the available methods are used in sequence just for the sake of an example.
        # Insert channel comment by omitting videoId
        # REMOVED AS IT IS NOT RELEVANT TO THE ERRRO REPORT. insert_comment(youtube, args.channelid, None, args.text)
        # Insert video comment
        # REMOVED AS IT IS NOT RELEVANT TO THE ERRRO REPORT. insert_comment(youtube, args.channelid, args.videoid, args.text)
        video_comments = get_comments(youtube, args.videoid, None)
        if video_comments:
          update_comment(youtube, video_comments[0])
    
      except HttpError, e:
        print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
      else:
        print "Inserted, listed and updated top-level comments."