【问题标题】:Thumbnail upload YouTube API v3 failing缩略图上传 YouTube API v3 失败
【发布时间】:2013-08-25 07:09:47
【问题描述】:

YouTube API v3 的文档非常糟糕。我已经多次报告了许多错误,但没有人做出反应。 我仍然必须使用这个 API 来上传缩略图。 该指南指出:

发布https://www.googleapis.com/youtube/v3/thumbnails/set

授权范围:

参数:

  • videoId: string videoId 参数指定为其提供自定义视频缩略图的 YouTube 视频 ID。

首先 - 网址错误。它必须是https://www.googleapis.com/upload/youtube/v3/thumbnails/set。 现在下面的代码,它使用Unirest:

final HttpResponse<String> response = Unirest.post("https://www.googleapis.com/upload/youtube/v3/thumbnails/set")
                    .header("Content-Type", "application/octet-stream")
                    .header("Authorization", accountService.getAuthentication(account).getHeader())
                    .field("videoId", videoid)
                    .field("thumbnail", thumbnail)
                    .asString();

收到的响应:

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "required",
    "message": "Required parameter: videoId",
    "locationType": "parameter",
    "location": "videoId"
   }
  ],
  "code": 400,
  "message": "Required parameter: videoId"
 }
}

这怎么可能? videoId 已设置! 有人玩过这部分 API 吗?

我可以将请求更改为

Unirest.post("https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=" + videoid)
                    .header("Content-Type", "application/octet-stream")
                    .header("Authorization", accountService.getAuthentication(account).getHeader())
                    .field("mediaUpload", thumbnail)
                    .asString();

这会给我这个错误:

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "backendError",
    "message": "Backend Error"
   }
  ],
  "code": 503,
  "message": "Backend Error"
 }
}

编辑: 与 Ibrahim Ulukaya 发布的 URL 相同的请求(参考指南中的原始 url):

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "wrongUrlForUpload",
    "message": "Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/thumbnails/set"
   }
  ],
  "code": 400,
  "message": "Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/thumbnails/set"
 }
}

【问题讨论】:

  • 只是同意 -- 如果您忘记了 URL 上的 /upload 前缀https://youtube.googleapis.com/upload/youtube/v3/thumbnails/set 将无济于事地响应 400 mediaBodyRequired 错误,即使正文和content-type 和二进制数据都正确提供。令人抓狂。

标签: java http rest youtube youtube-api


【解决方案1】:

给出的答案甚至不接近正确!如果您在正文中没有图片的情况下发布到此 URL:

https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=VIDEO_ID&uploadType=resumable

您将收到此错误:

“400:mediaBodyRequired”

本页底部的 YouTube 文档中描述了此错误:

https://developers.google.com/youtube/v3/docs/thumbnails/set

作为:

“请求中不包含图片内容。”

虽然他们的文档遗漏了很多东西(想想 categoryId),但他们已经死在这里了,因为我刚刚尝试了 Ibrahim 发布的第一个解决方案并收到了错误。尽管他声明不提供正文中的图像数据,但文档和我自己的研究表明完全相反。

解决方案是发布到包含图片正文的此 URL。这样做时,我收到了以下回复:

{ "kind": "youtube#thumbnailSetResponse", "etag": "\"kYnGHzMaBhcGeLrcKRx6PAIUosY/lcDPfygjJkG-yyzdBp0dKhY2xMY\"", "items": [ { "default": { "url": "//i. ytimg.com/vi/fyBx3v1gmbM/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "//i.ytimg.com/vi/fyBx3v1gmbM/mqdefault. jpg", "width": 320, "height": 180 }, "high": { "url": "//i.ytimg.com/vi/fyBx3v1gmbM/hqdefault.jpg", "width": 480, "高度”:360 },“标准”:{“url”:“//i.ytimg.com/vi/fyBx3v1gmbM/sddefault.jpg”,“宽度”:640,“高度”:480 },“最大分辨率”: { "url": "//i.ytimg.com/vi/fyBx3v1gmbM/maxresdefault.jpg", "width": 1280, "height": 720 } } ] }

不幸的是,它实际上并没有更改缩略图,但我认为这是他们的 API 服务器和他们的缩略图处理排队的问题。它确实返回了成功的响应。不知道为什么缩略图没有改变。

【讨论】:

    【解决方案2】:

    我们已经解决了这个问题,如果您不想使用该库,请按照以下步骤操作。

    1) 发布https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=VIDEO_ID&uploadType=resumable 身体空虚

    2) 取回响应的 Location: 标头中的 URL,并使用 Content-Type: image/png 和正文中的缩略图 POST 到该 URL

    【讨论】:

    • 我确实想使用该库,但我不能使用不完整/不工作的库:D。没有对此进行测试,但相信您现在已修复。
    • 很好的答案;可以添加到官方文档中吗?
    • 是否有完整的示例说明如何执行此操作?
    • 这看起来也需要用户交互。我正在寻找没有交互的服务器到服务器设置。现在我的系统为我生成我的视频并将它们发布到我的频道。现在我想为该帖子添加一个自定义缩略图,但似乎不是一个选项。
    【解决方案3】:

    网址将被修复。

    您还需要在您的频道中拥有特定权限才能设置自定义缩略图。

    我们的示例代码中有 PHPPython 示例有效。

    这是 Java 的,我刚刚编写并测试过,它可以工作。

    /*
     * Copyright (c) 2013 Google Inc.
     *
     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
     * in compliance with the License. You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software distributed under the License
     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     * or implied. See the License for the specific language governing permissions and limitations under
     * the License.
     */
    
    package com.google.api.services.samples.youtube.cmdline.youtube_cmdline_uploadthumbnail_sample;
    
    import com.google.api.client.auth.oauth2.Credential;
    import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
    import com.google.api.client.extensions.java6.auth.oauth2.FileCredentialStore;
    import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
    import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
    import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
    import com.google.api.client.googleapis.json.GoogleJsonResponseException;
    import com.google.api.client.googleapis.media.MediaHttpUploader;
    import com.google.api.client.googleapis.media.MediaHttpUploaderProgressListener;
    import com.google.api.client.http.HttpTransport;
    import com.google.api.client.http.InputStreamContent;
    import com.google.api.client.http.javanet.NetHttpTransport;
    import com.google.api.client.json.JsonFactory;
    import com.google.api.client.json.jackson2.JacksonFactory;
    import com.google.api.services.youtube.YouTube;
    import com.google.api.services.youtube.YouTube.Thumbnails.Set;
    import com.google.api.services.youtube.model.ThumbnailSetResponse;
    import com.google.common.collect.Lists;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.List;
    
    /**
     * This sample uploads and sets a custom thumbnail for a video by:
     *
     *  1. Uploading a image utilizing "MediaHttpUploader" 2. Setting the uploaded image as a custom
     * thumbnail to the video via "youtube.thumbnails.set" method
     *
     * @author Ibrahim Ulukaya
     */
    public class UploadThumbnail {
    
      /**
       * Global instance of the HTTP transport.
       */
      private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
    
      /**
       * Global instance of the JSON factory.
       */
      private static final JsonFactory JSON_FACTORY = new JacksonFactory();
    
      /**
       * Global instance of Youtube object to make all API requests.
       */
      private static YouTube youtube;
    
      /* Global instance of the format used for the image being uploaded (MIME type). */
      private static String IMAGE_FILE_FORMAT = "image/png";
    
    
    
      /**
       * Authorizes the installed application to access user's protected data.
       *
       * @param scopes list of scopes needed to run youtube upload.
       */
      private static Credential authorize(List<String> scopes) throws IOException {
    
        // Load client secrets.
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
            new InputStreamReader(UploadThumbnail.class.getResourceAsStream("/client_secrets.json")));
    
        // Checks that the defaults have been replaced (Default = "Enter X here").
        if (clientSecrets.getDetails().getClientId().startsWith("Enter")
            || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
          System.out.println(
              "Enter Client ID and Secret from https://code.google.com/apis/console/?api=youtube"
              + "into youtube-cmdline-uploadthumbnail-sample/src/main/resources/client_secrets.json");
          System.exit(1);
        }
    
        // Set up file credential store.
        FileCredentialStore credentialStore = new FileCredentialStore(
            new File(System.getProperty("user.home"), ".credentials/youtube-api-uploadthumbnail.json"),
            JSON_FACTORY);
    
        // Set up authorization code flow.
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, scopes).setCredentialStore(credentialStore)
            .build();
    
        // Build the local server and bind it to port 8080
        LocalServerReceiver localReceiver = new LocalServerReceiver.Builder().setPort(8080).build();
    
        // Authorize.
        return new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user");
      }
    
      /**
       * This is a very simple code sample that looks up a user's channel, then features the most
       * recently uploaded video in the bottom left hand corner of every single video in the channel.
       *
       * @param args command line args (not used).
       */
      public static void main(String[] args) {
    
        // An OAuth 2 access scope that allows for full read/write access.
        List<String> scopes = Lists.newArrayList("https://www.googleapis.com/auth/youtube");
    
        try {
          // Authorization.
          Credential credential = authorize(scopes);
    
          // YouTube object used to make all API requests.
          youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(
              "youtube-cmdline-addfeaturedvideo-sample").build();
    
          // Get the user selected video Id.
          String videoId = getVideoIdFromUser();
          System.out.println("You chose " + videoId + " to upload a thumbnail.");
    
          // Get the user selected local image file to upload.
          File imageFile = getImageFromUser();
          System.out.println("You chose " + imageFile + " to upload.");
    
          InputStreamContent mediaContent = new InputStreamContent(
              IMAGE_FILE_FORMAT, new BufferedInputStream(new FileInputStream(imageFile)));
          mediaContent.setLength(imageFile.length());
    
          // Create a request to set the selected mediaContent as the thumbnail of the selected video.
          Set thumbnailSet = youtube.thumbnails().set(videoId, mediaContent);
    
          // Set the upload type and add event listener.
          MediaHttpUploader uploader = thumbnailSet.getMediaHttpUploader();
    
          /*
           * Sets whether direct media upload is enabled or disabled. True = whole media content is
           * uploaded in a single request. False (default) = resumable media upload protocol to upload
           * in data chunks.
           */
          uploader.setDirectUploadEnabled(false);
    
          MediaHttpUploaderProgressListener progressListener = new MediaHttpUploaderProgressListener() {
            @Override
            public void progressChanged(MediaHttpUploader uploader) throws IOException {
              switch (uploader.getUploadState()) {
                case INITIATION_STARTED:
                  System.out.println("Initiation Started");
                  break;
                case INITIATION_COMPLETE:
                  System.out.println("Initiation Completed");
                  break;
                case MEDIA_IN_PROGRESS:
                  System.out.println("Upload in progress");
                  System.out.println("Upload percentage: " + uploader.getProgress());
                  break;
                case MEDIA_COMPLETE:
                  System.out.println("Upload Completed!");
                  break;
                case NOT_STARTED:
                  System.out.println("Upload Not Started!");
                  break;
              }
            }
          };
          uploader.setProgressListener(progressListener);
    
          // Execute upload and set thumbnail.
          ThumbnailSetResponse setResponse = thumbnailSet.execute();
    
          // Print out returned results.
          System.out.println("\n================== Uploaded Thumbnail ==================\n");
          System.out.println("  - Url: " + setResponse.getItems().get(0).getDefault().getUrl());
    
        } catch (GoogleJsonResponseException e) {
          System.err.println("GoogleJsonResponseException code: " + e.getDetails().getCode() + " : "
              + e.getDetails().getMessage());
          e.printStackTrace();
    
        } catch (IOException e) {
          System.err.println("IOException: " + e.getMessage());
          e.printStackTrace();
        }
      }
    
      /*
       * Prompts for a video ID from standard input and returns it.
       */
      private static String getVideoIdFromUser() throws IOException {
    
        String title = "";
    
        System.out.print("Please enter a video Id to update: ");
        BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
        title = bReader.readLine();
    
        if (title.length() < 1) {
          // If nothing is entered, exits
          System.out.print("Video Id can't be empty!");
          System.exit(1);
        }
    
        return title;
      }
    
      /*
       * Prompts for the path of the image file to upload from standard input and returns it.
       */
      private static File getImageFromUser() throws IOException {
    
        String path = "";
    
        System.out.print("Please enter the path of the image file to upload: ");
        BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
        path = bReader.readLine();
    
        if (path.length() < 1) {
          // If nothing is entered, exits
          System.out.print("Path can not be empty!");
          System.exit(1);
        }
    
        return new File(path);
      }
    }
    

    【讨论】:

    • 我已经更新了问题。上面发布了带有初始 url 的响应。我还需要哪些其他权限?
    • 这就是我讨厌谷歌的原因:支持极好的谷歌群已经关闭。我们必须使用 stackoverflow——这是一个很棒的网站——但只有少数用户有使用 youtube-api 的经验。 java 示例仍然不在线。您在整个文档中发布和发布的 url 无效。问题跟踪器被忽略。易卜拉欣,我真的必须以旧方式写信以获得更好的工作错误修正 API 吗? (这不仅仅是需要注意的缩略图)。还是我必须开始 @Google 工作?
    • "您还需要在您的频道中拥有特定权限才能设置自定义缩略图。"此权限设置是否可通过 API 获得?我为未经验证的帐户检查了“userEmailIsVerified”,并将其设置为 true。当我尝试使用该帐户上传拇指时,返回的错误是“禁止”,而经过验证的帐户工作正常。所以: - 我们可以查询帐户是否已验证/启用拇指? - 有没有办法通过 API 为用户启动验证?
    • 没有API可以查询,可以在youtube.com/account_features的features下看到。一般来说,如果您的帐户信誉良好且经过验证,您可以上传缩略图。
    猜你喜欢
    • 2020-12-30
    • 2015-08-11
    • 2016-05-03
    • 2021-06-13
    • 2015-01-18
    • 1970-01-01
    • 2021-10-07
    • 2021-05-21
    • 2016-03-23
    相关资源
    最近更新 更多