0

I am having issues adding captions to videos uploaded to my company's youtube channels. I want to do it with Google's Youtube Api v3 in .Net. I am able to successfully upload videos to the channels, but I get the following error when trying to send captions: "System.Net.Http.HttpRequestException: Response status code does not indicate success: 403 (Forbidden)."

As far as I can tell, my credentials do not forbid me from uploading captions. I am able to upload videos without any problem.

I created the refresh token using the instructions here: Youtube API single-user scenario with OAuth (uploading videos)

This is the code I'm using to create the YouTubeService object:

    private YouTubeService GetYouTubeService()
    {
        string clientId = "clientId";
        string clientSecret = "clientSecret";
        string refreshToken = "refreshToken";
        try
        {
            ClientSecrets secrets = new ClientSecrets()
            {
                ClientId = clientId,
                ClientSecret = clientSecret
            };

            var token = new TokenResponse { RefreshToken = refreshToken };
            var credentials = new UserCredential(new GoogleAuthorizationCodeFlow(
                new GoogleAuthorizationCodeFlow.Initializer
                {
                    ClientSecrets = secrets,
                    Scopes = new[] { YouTubeService.Scope.Youtube, YouTubeService.Scope.YoutubeUpload, YouTubeService.Scope.YoutubeForceSsl }
                }),
                "user",
                token);

            var service = new YouTubeService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credentials,
                ApplicationName = "TestProject"
            });

            service.HttpClient.Timeout = TimeSpan.FromSeconds(360);
            return service;
        }
        catch (Exception ex)
        {
            Log.Error("YouTube.GetYouTubeService() => Could not get youtube service. Ex: " + ex);
            return null;
        }

    }

And here is the code I have for uploading the caption file:

    private void UploadCaptionFile(String videoId)
    {
        try
        {
            Caption caption = new Caption();
            caption.Snippet = new CaptionSnippet();
            caption.Snippet.Name = videoId + "_Caption";
            caption.Snippet.Language = "en";
            caption.Snippet.VideoId = videoId;
            caption.Snippet.IsDraft = false;

            WebRequest req = WebRequest.Create(_urlCaptionPath);
            using (Stream stream = req.GetResponse().GetResponseStream())
            {
                CaptionsResource.InsertMediaUpload captionInsertRequest = _youtubeService.Captions.Insert(caption, "snippet", stream, "*/*");
                captionInsertRequest.Sync = true;
                captionInsertRequest.ProgressChanged += captionInsertRequest_ProgressChanged;
                captionInsertRequest.ResponseReceived += captionInsertRequest_ResponseReceived;

                IUploadProgress result = captionInsertRequest.Upload();
            }
        }
        catch (Exception ex)
        {
            Log.Error("YouTube.UploadCaptionFile() => Unable to upload caption file. Ex: " + ex);
        }
    }

    void captionInsertRequest_ResponseReceived(Caption obj)
    {
        Log.Info("YouTube.captionInsertRequest_ResponseReceived() => Caption ID " + obj.Id + " was successfully uploaded for this clip.");
        Utility.UpdateClip(_videoClip);
    }

    void captionInsertRequest_ProgressChanged(IUploadProgress obj)
    {
        switch (obj.Status)
        {
            case UploadStatus.Uploading:
                Console.WriteLine("{0} bytes sent.", obj.BytesSent);
                break;

            case UploadStatus.Failed:
                Log.Error("YouTube.UploadCaptionFile() => An error prevented the upload from completing. " + obj.Exception);
                break;
        }
    }

I have spent the past couple days working on this issue, and I have been unable to make any progress. The YouTubeApi v3 doesn't have much information on adding captions. All I was able to find was some old information for v2, which required some POST calls that require keys that I don't have. I would like to be able to add the captions using the API's build-in methods for doing so.

If anyone has experience dealing with this issue, I would greatly appreciate any help you could offer.

EDIT:

Here is my code for sending the videos to YouTube.

    public string UploadClipToYouTube()
    {
        try
        {
            var video = new Google.Apis.YouTube.v3.Data.Video();
            video.Snippet = new VideoSnippet();
            video.Snippet.Title = _videoClip.Name;
            video.Snippet.Description = _videoClip.Description;
            video.Snippet.Tags = GenerateTags();
            video.Snippet.DefaultAudioLanguage = "en";
            video.Snippet.DefaultLanguage = "en";
            video.Snippet.CategoryId = "22";
            video.Status = new VideoStatus();
            video.Status.PrivacyStatus = "unlisted";

            WebRequest req = WebRequest.Create(_videoPath);
            using (Stream stream = req.GetResponse().GetResponseStream())
            {
                VideosResource.InsertMediaUpload insertRequest = _youtubeService.Videos.Insert(video, "snippet, status", stream, "video/*");
                insertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
                insertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;

                insertRequest.Upload();
            }
            return UploadedVideoId;
        }
        catch (Exception ex)
        {
            Log.Error("YouTube.UploadClipToYoutube() => Error attempting to authenticate for YouTube. Ex: " + ex);
            return "";
        }
    }

    void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
    {
        switch (progress.Status)
        {
            case UploadStatus.Uploading:
                Log.Info("YouTube.videosInsertRequest_ProgressChanged() => Uploading to Youtube. " + progress.BytesSent + " bytes sent.");
                break;

            case UploadStatus.Failed:
                Log.Error("YouTube.videosInsertRequest_ProgressChanged() => An error prevented the upload from completing. Exception: " + progress.Exception);
                break;
        }
    }

    void videosInsertRequest_ResponseReceived(Google.Apis.YouTube.v3.Data.Video video)
    {
        Log.Info("YouTube.videosInsertRequest_ResponseReceived() => Video was successfully uploaded to YouTube.  The YouTube id is " + video.Id);
        UploadedVideoId = video.Id;
        UploadCaptionFile(video.Id);
    }
Community
  • 1
  • 1
Chelsea
  • 3
  • 4
  • Few questions. With regards to the authentication, are you using the same process as with the upload? With the error being *403 forbidden* (this is obvious, but I think is also worth asking) does your Caption data comply with [constraints](https://developers.google.com/youtube/v3/docs/captions/insert#request). Also, I've seen this [similar post](http://stackoverflow.com/questions/31823160/uploading-captions-using-youtube-api-v3-dotnet-c-null-error-challenging), only difference is the error he's receiving, have you tried checking his codes out? :) – AL. Apr 08 '16 at 07:07
  • The video upload process is almost identical to the caption upload process. I will update my original post with the video upload process I'm using. I have "YouTubeService.Scope.YoutubeForceSsl" as one of the scopes when creating the credentials, so everything should comply with the constraints. I've looked at that similar post; actually, one of the repliers is a former coworker who was working on this project before he left and I took over. Unfortunately, the code he posted doesn't work. – Chelsea Apr 08 '16 at 15:19
  • 1
    @Chelsea This isn't `v3`. Version 3 uses `GoogleWebAuthorizationBroker` and `FileDataStore` for Oauth... Also it uses `await` and `async` operations that prevent locking up the application. Are you getting the new version mixed possibly with the old versions? Also I suspect you are not providing a username for your request, this is possible for the errors or you have left this out for security reasons... – Trevor Apr 08 '16 at 20:37

1 Answers1

1

Alright, I whipped up something really quick for you (honestly about 15 minutes) that I translated from Java. First there are more than a few things I have noticed with your current code, but this is not CodeReview.

The YouTubeApi v3 doesn't have much information on adding captions. All I was able to find was some old information for v2

You are correct about this, it doesn't at this time (v3), but hopefully sometime in the near future. This doesn't stop us from modifying v2 though to our advantage as the api are very similar...

Code Tried & Tested

private async Task addVideoCaption(string videoID) //pass your video id here..
        {
            UserCredential credential;
            //you should go out and get a json file that keeps your information... You can get that from the developers console...
            using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
            {
                credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    new[] { YouTubeService.Scope.YoutubeForceSsl, YouTubeService.Scope.Youtube, YouTubeService.Scope.Youtubepartner },
                    "ACCOUNT NAME HERE",
                    CancellationToken.None,
                    new FileDataStore(this.GetType().ToString())
                );
            }
            //creates the service...
            var youtubeService = new Google.Apis.YouTube.v3.YouTubeService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = this.GetType().ToString(),
            });

            //create a CaptionSnippet object...
            CaptionSnippet capSnippet = new CaptionSnippet();
            capSnippet.Language = "en";
            capSnippet.Name = videoID + "_Caption";
            capSnippet.VideoId = videoID;
            capSnippet.IsDraft = false;

            //create new caption object
            Caption caption = new Caption();       

            //set the completed snippet to the object now...
            caption.Snippet = capSnippet;

            //here we read our .srt which contains our subtitles/captions...
            using (var fileStream = new FileStream("filepathhere", FileMode.Open))
            {
                //create the request now and insert our params...
                var captionRequest = youtubeService.Captions.Insert(caption, "snippet",fileStream,"application/atom+xml");

                //finally upload the request... and wait.
                await captionRequest.UploadAsync();
            }

        }

Here's an example .srt file if you do not know what one look's like or how it's formatted.

1
00:00:00,599 --> 00:00:03,160
>> Caption Test zaggler@ StackOverflow

2
00:00:03,160 --> 00:00:05,770
>> If you're reading this it worked!

YouTube Video Proof. It's a short clip about 5 seconds just to show you that it work's and what it look's like. AND... No the video isn't mine, grabbed it for testing ONLY :)

Good Luck and Happy Programming!

Trevor
  • 7,777
  • 6
  • 31
  • 50
  • Welcome, glad I could help! – Trevor Apr 12 '16 at 15:48
  • This section:credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( GoogleClientSecrets.Load(stream).Secrets, new[] { YouTubeService.Scope.YoutubeForceSsl, YouTubeService.Scope.Youtube, YouTubeService.Scope.Youtubepartner }, "ACCOUNT NAME HERE", CancellationToken.None, new FileDataStore(this.GetType().ToString()) ); – Steven Melendez Jan 24 '18 at 21:28