0

Anyone familiar with the V3 YouTube API suggest what I might be doing wrong:

    Dim Service As YoutubeService = GetYouTubeService()

    Dim SourceVideo As String = "C:\TempMedia\Wildlife.wmv"

    Dim Meta As New Video
    Meta.Snippet = New VideoSnippet
    Meta.Snippet.Title = "Test Wildlife Video"
    Meta.Snippet.Description = "This is a test video only"
    Meta.Snippet.CategoryId = "Animals"
    Meta.Snippet.Tags = New List(Of String)
    Meta.Snippet.Tags.Add("Test")
    Meta.Status = New VideoStatus
    Meta.Status.PrivacyStatus = "unlisted"

    Using fs As New FileStream(SourceVideo, FileMode.Open, FileAccess.Read, FileShare.Inheritable)
        Dim UploadRequest As VideosResource.InsertMediaUpload = Service.Videos.Insert(Meta, "snippet,statistics,status", fs, "application/octet-stream")
        UploadRequest.Upload()
        Dim Uploaded = UploadRequest.ResponseBody
    End Using

After thinking for a bit, this is throwing a 500 Internal Server Error in the SendChunk

System.Net.WebException was unhandled   HResult=-2146233079   Message=The remote server returned an error: (500) Internal Server Error.   Source=System   StackTrace:
       at System.Net.HttpWebRequest.GetResponse()
       at Google.Apis.Upload.ResumableUpload`1.SendChunk(Stream stream, Uri uri, Int64 position) in c:\code.google.com\google-api-dotnet-client\default\Tools\BuildRelease\bin\Debug\12-20-2012\default\Src\GoogleApis\Apis\Upload\ResumableUpload.cs:line 452
       at Google.Apis.Upload.ResumableUpload`1.Upload() in c:\code.google.com\google-api-dotnet-client\default\Tools\BuildRelease\bin\Debug\12-20-2012\default\Src\GoogleApis\Apis\Upload\ResumableUpload.cs:line 315
       at QUICTools.Workflow.Social.YouTube.QuicYouTube.TestUpload() in C:\Users\kenny.munro.ZAZA\Documents\Visual Studio 2010\Projects\QUIC_V2.0\QUICTools.Workflow.Social.YouTube\QuicYouTube.vb:line 37
       at QLTest.Form1.SimpleButton1_Click(Object sender, EventArgs e) in C:\Users\kenny.munro.ZAZA\Documents\Visual Studio 2010\Projects\QUIC_V2.0\QLTest\Form1.vb:line 4
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at DevExpress.XtraEditors.BaseButton.OnClick(EventArgs e)
       at DevExpress.XtraEditors.BaseButton.OnKeyUp(KeyEventArgs e)
       at System.Windows.Forms.Control.ProcessKeyEventArgs(Message& m)
       at System.Windows.Forms.Control.ProcessKeyMessage(Message& m)
       at System.Windows.Forms.Control.WmKeyChar(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at DevExpress.Utils.Controls.ControlBase.WndProc(Message& m)
       at DevExpress.XtraEditors.BaseControl.WndProc(Message& msg)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at QLTest.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()   InnerException:

I have to admit I'm now stumped. Does anyone have a working example of an upload to YouTube using the V3 dotnet API or suggestions where this might be going wrong?

UPDATE

I've been doing some more analysis of this using Fiddler. First, I set added a line to set the chunkSize = 10000. I can now see loads of chunks being uploaded just fine and returning 308 response codes. The error is being returned by the final partial chunk:

PUT /upload/youtube/v3/videos?uploadType=resumable&alt=json&part=snippet%2Cstatus&upload_id=AEnB2UqVVIYV1YyYk27JhhFj_U2WzbK0_ghq0QIRsO1dB1caaMrazd-wlULFZVxvM_pHDZFJkVmUJbYw4oVicI2rfJujdXy4ZQ HTTP/1.1
Content-Range: bytes 26250000-26255829/26255830
Host: www.googleapis.com
Content-Length: 5830

500 Internal Server Error (application/json)

Not too sure how this could be anything I'm doing wrong but would appreciate some input/validation from someone who has this working.

For completeness, here's the initial insert command - again, all looks fine to me:

POST /upload/youtube/v3/videos?uploadType=resumable&alt=json&part=snippet%2Cstatus HTTP/1.1
X-Upload-Content-Type: video/x-ms-wmv
X-Upload-Content-Length: 26255830
Authorization: Bearer ya29.AHES6ZTQsUz4SI-jOnCO8kL3hg_L...
Content-Type: application/json
Host: www.googleapis.com
Content-Length: 168
Connection: Keep-Alive

{"snippet":{"categoryId":"Entertainment","description":"This is a test video only","tags":["Test"],"title":"Test Wildlife Video"},"status":{"privacyStatus":"unlisted"}}
HTTP/1.1 200 OK
Server: HTTP Upload Server Built on Feb 6 2013 15:53:54 (1360194834)
Location: https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&alt=json&part=snippet%2Cstatus&upload_id=AEnB2UqVVIYV1YyYk27JhhFj_U2WzbK0_ghq0QIRsO1dB1caaMrazd-wlULFZVxvM_pHDZFJkVmUJbYw4oVicI2rfJujdXy4ZQ
Date: Tue, 19 Feb 2013 13:58:18 GMT
Pragma: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Cache-Control: no-cache, no-store, must-revalidate
Content-Length: 0
Content-Type: text/html; charset=UTF-8

2 Answers2

1

CategoryId is a number. You can use this example to download a list of the ID (number) and the Title of all of the valid categories. This example puts the ID and Title into a custom class object and adds each class object as an item in a ComboBox control.

    OAUth2Credential = Nothing
    Try
        GetGredentials.Wait()
        objYouTubeService = New YouTubeService(New BaseClientService.Initializer() With { _
             .HttpClientInitializer = OAUth2Credential, _
             .ApplicationName = Assembly.GetExecutingAssembly().GetName().Name})
    Catch ex As Exception
        MsgBox(ex.Message)
        End
    End Try
    Dim objCategories As VideoCategoryListResponse = Nothing
    Try
        Dim objRequest As VideoCategoriesResource.ListRequest = New VideoCategoriesResource.ListRequest(objYouTubeService, "id,snippet")
        objRequest.Hl = "en_US"
        objRequest.RegionCode = "US"
        objCategories = objRequest.Execute
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
    cmbCategory.DisplayMember = "Title"
    cmbCategory.ValueMember = "Id"
    For Each obj As VideoCategory In objCategories.Items
        cmbCategory.Items.Add(New CategoryClass(obj.Id, obj.Snippet.Title))
        If obj.Snippet.Title.Contains("News") Then
            intDefaultCategoryIndex = cmbCategory.Items.Count - 1
        End If
    Next
    cmbCategory.SelectedIndex = intDefaultCategoryIndex
    ...

Below is how I fill OAuth2Credential.

Private Async Function GetGredentials() As Task
     Try
         '
         ' ClientId and ClientSecret are found in your client_secret_*****.apps.googleusercontent.com.json file downloaded from 
         ' the Google Developers Console ( https://console.developers.google.com). 
         ' This sample shows the ClientID and ClientSecret in the source code. 
         ' Other samples in the sample library show how to read the Client Secrets from the              ' client_secret_*****.apps.googleusercontent.com.json file. 
         '
         OAUth2Credential = Await GoogleWebAuthorizationBroker.AuthorizeAsync( _
             New ClientSecrets With {.ClientId = "Your Client ID goes here ..............................................", _
                                     .ClientSecret = "Your Client Secret goes here."}, _
                                 {YouTubeService.Scope.Youtube}, "user", CancellationToken.None)
         If OAUth2Credential IsNot Nothing Then
             If OAUth2Credential.Token IsNot Nothing Then
                 AddToLog(String.Concat("Token Issued: ", OAUth2Credential.Token.Issued))
             End If
         End If
     Catch ex As Exception
         MsgBox(ex.Message, MsgBoxStyle.Critical, "Google Authorization")
         End
     End Try
 End Function

This is what my custom class looks like:

Friend Class CategoryClass
Dim m_Id As String
Dim m_Title As String
Sub New(ByVal Id As String, ByVal Title As String)
     m_Id = Id
     m_Title = Title
End Sub
Property ID As String
      Get
         ID = m_Id
     End Get
     Set(value As String)
         m_Id = value
     End Set
End Property
Property Title As String
     Get
         Title = m_Title
     End Get
     Set(value As String)
         m_Title = value
     End Set
End Property
End Class
Mike Meinz
  • 506
  • 3
  • 9
  • Could you please show me how you build the OAUth2Credential varible – Pomster Oct 01 '14 at 11:43
  • Sorry for the delay in responding. I was out of the country without a PC. I modified my answer to include the **GetCredentials** subroutine. This code is from my example program found in my tip [article](http://www.codeproject.com/Tips/801604/Sample-VB-NET-program-using-Google-APIs-for-NET-V). – Mike Meinz Oct 03 '14 at 21:54
0

Since you are uploading by chunks why don't you capture the progress and responsereceived events so you can have more info of what's happening. Here's how you can do it:

UploadRequest.ChunkSize = 10000;
UploadRequest.ProgressChanged += UploadRequest_ProgressChanged;
UploadRequest.ResponseReceived += UploadRequest_ResponseReceived;

Sub UploadRequest_ProgressChanged(obj As Google.Apis.Upload.IUploadProgress)
    ' check if the upload has been completed            
    If obj.Status = Google.Apis.Upload.UploadStatus.Completed Then
        ' do something here
    End If

    ' or check the status and handle it appropriately
    ' see "Google.Apis.Upload.UploadStatus" for possible status returned


    ' or check the details of the exception here
    If obj.Exception IsNot Nothing Then
        Console.WriteLine(obj.Exception.Message)
    End If
End Sub

Sub UploadRequest_ResponseReceived(Google.Apis.Youtube.v3.Data.Video obj)
    ' your video object will be available here once the upload is done

End Sub

NOTE: I wrote this in C# and used a site to convert it to VB so there may be some syntax error, I'm sure you know how to fix it.

von v.
  • 16,868
  • 4
  • 60
  • 84