3

c# ライブラリを使用せずに、YouTube API の v3 を使用してファイルをアップロードしようとしています。いくつかの一般的な API (YouTube、Vimeo、Facebook など) を使用できるようにする独自のライブラリを作成しているため、ライブラリを実際に使用することはできません。

私はすでにアクセス トークンとリフレッシュ トークンを取得していますが、これで問題ありません。次に、ここで定義されている YouTube の再開可能なアップロードを使用してファイルをアップロードする必要があります。

https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol

しかし、何らかの理由でコードに 401 Unauthorized エラーが返されますが、その理由がわかりません。リクエストを作成している私のコードは次のとおりです。

    private void CreateUploadRequest(SynchronisedAsset asset)
    {
        var endPoint = api.ApiUrl + "/videos?uploadType=resumable&part=snippet&key=" + api.Tokens.ConsumerKey; // read for the different ways to interact with videos https://developers.google.com/youtube/v3/docs/#Videos
        var maxSize = 68719476736; // 64 gig

        try
        {
            var location = CompanyProvider.GetUploadLocation(this.baseUploadDirectory, companyId, FileType.Asset);
            var filePath = System.IO.Path.Combine(location, asset.FileName);
            using (var data = new FileStream(filePath, FileMode.Open))
            {
                if (maxSize > data.Length && (asset.MimeType.ToLower().StartsWith("video/") || asset.MimeType.ToLower().Equals("application/octet-stream")))
                {
                    var json = "{ \"snippet\": { \"title\": \"" + asset.FileName + "\", \"description\": \"This is a description of my video\" } }";
                    var buffer = Encoding.ASCII.GetBytes(json);

                    var request = WebRequest.Create(endPoint);
                    request.Headers[HttpRequestHeader.Authorization] = string.Format("Bearer {0}", api.Tokens.AccessToken);
                    request.Headers["X-Upload-Content-Length"] = data.Length.ToString();
                    request.Headers["X-Upload-Content-Type"] = asset.MimeType;
                    request.ContentType = "application/json; charset=UTF-8";
                    request.ContentLength = buffer.Length;
                    request.Method = "POST";

                    using (var stream = request.GetRequestStream())
                    {
                        stream.Write(buffer, 0, (int)buffer.Length);
                    }

                    var response = request.GetResponse();
                }
            }
        }
        catch (Exception ex)
        {
            eventLog.WriteEntry("Error uploading to youtube.\nEndpoint: " + endPoint + "\n" + ex.ToString(), EventLogEntryType.Error);
        }
    }

api.ApiUrl はhttps://www.googleapis.com/youtube/v3です。キーが必要かどうかはわかりません。ドキュメントには表示されていませんが、未承認の問題を解決できるかどうかを確認するために追加しました。また、キーがなければ、アップロード先のアカウントをどのように知るのでしょうか?

私のコードの何が問題なのか誰にもわかりますか?

どんな助けでも大歓迎です。

更新 1

少し時間をかけて整理した後、アップロードを試みる前に YouTube の資格情報をチェックするコードを追加しました。これは、次のコードで行われます。

    public string GetAuthorizeApplicationUrl()
    {
        var sb = new StringBuilder();
        var dictionary = new Dictionary<string, string>
        {
            {"client_id", Tokens.ConsumerKey},
            {"redirect_uri", callbackUrl},
            {"response_type", "code"},
            {"scope", "https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtubepartner"},
            {"approval_prompt", "force"},
            {"access_type", "offline"},
            {"state", ""}
        };

        sb.Append(requestTokenUrl);
        foreach (var parameter in dictionary)
        {
            var query = (sb.ToString().Contains("?")) ? "&" : "?";
            sb.Append(query + parameter.Key + "=" + parameter.Value);
        }

        return sb.ToString();
    }

このコードは、ユーザーにアクセスを求めるための URL を作成する役割を果たします。

リターン URL に返されるコードを使用して、次のコードを呼び出します。

    public void RequestAccessToken(string code)
    {
        var dictionary = new Dictionary<string, string>
        {
            {"code", code},
            {"client_id", Tokens.ConsumerKey},
            {"client_secret", Tokens.ConsumerSecret},
            {"redirect_uri", callbackUrl},
            {"grant_type", "authorization_code"}
        };
        var parameters = NormalizeParameters(dictionary);

        var resultString = "";

        using (var wc = new WebClient())
        {
            //wc.Headers[HttpRequestHeader.Host] = "POST";
            wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            resultString = wc.UploadString(requestAccessTokenUrl, parameters);
        }

        var json = JObject.Parse(resultString);

        Tokens.AccessToken = json["access_token"].ToString();
        Tokens.RefreshToken = (json["refresh_token"] != null) ? json["refresh_token"].ToString() : null;
        Tokens.Save(companyId);
    }

アプリをオフラインとして宣言したので、API 呼び出しを行うときに、次のコードを使用できます。

    public bool CheckAccessToken()
    {
        try
        {
            RefreshToken(); // Get and store our new tokens

            return true;
        }
        catch
        {
            return false;
        }
    }

    private void RefreshToken()
    {
        var dictionary = new Dictionary<string, string>
        {
            {"refresh_token", Tokens.RefreshToken},
            {"client_id", Tokens.ConsumerKey},
            {"client_secret", Tokens.ConsumerSecret},
            {"grant_type", "refresh_token"}
        };
        var parameters = NormalizeParameters(dictionary);

        var resultString = "";

        using (var wc = new WebClient())
        {
            //wc.Headers[HttpRequestHeader.Host] = "POST";
            wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            resultString = wc.UploadString(requestAccessTokenUrl, parameters);
        }

        var json = JObject.Parse(resultString);

        Tokens.AccessToken = json["access_token"].ToString();
        Tokens.Save(companyId);
    }

私のWindowsサービスには、次のコードがあります。

    public void SynchroniseAssets(IEnumerable<SynchronisedAsset> assets)
    {
        if (api.CheckAccessToken())
        {
            foreach (var asset in assets)
            {
                var uploadAssetThread = new Thread(() => CreateUploadRequest(asset));
                uploadAssetThread.Start(); // Upload our assets at the same time
            }
        }
    }

ご覧のとおり、上記の元のコードを呼び出します。json に解析するときに発生するエラーは次のとおりです。

{
   "error":{
      "errors":[
     {
        "domain":"youtube.header",
        "reason":"youtubeSignupRequired",
        "message":"Unauthorized",
        "locationType":"header",
        "location":"Authorization"
     }
      ],
      "code":401,
      "message":"Unauthorized"
   }
}

ですから、誰かがそれが何を意味するのかを理解するのを手伝ってくれたら、それは素晴らしいことです.

乾杯、

/r3plica

4

2 に答える 2

8

「youtubeSignupRequired」という理由は通常、YouTube アカウントが正しく設定されていないか、まだ YouTube チャンネルを作成していないことを意味します。これは、動画をアップロードする前の要件です。Google がこの場合のエラー メッセージを改善し、もう少し冗長にすることができれば素晴らしいことです。

于 2013-07-12T18:48:19.650 に答える
4

401 Unautorized を返す問題は、アクセスしようとしていたアカウントに YouTube アカウントが関連付けられていなかったためです。

于 2013-06-26T13:37:59.857 に答える