問題描述
我不知道如何在 C# YouTube API V3 中恢復中斷的上傳.
I can't work out how to resume an interrupted upload in V3 of the C# YouTube API.
我現有的代碼使用 V1 并且工作正常,但我正在切換到 V3.
My existing code uses V1 and works fine but I'm switching to V3.
如果我在不更改任何內容的情況下調用 UploadAsync(),它會從頭開始.使用 Fiddler,我可以看到未遵循 此處給出的協議,并且上傳重新開始.
If I call UploadAsync() without changing anything, it starts from the beginning. Using Fiddler, I can see the protocol given here is not followed and the upload restarts.
我嘗試按照 V1 設置流中的位置,但沒有可用的 ResumeAsync() 方法.
I've tried setting the position within the stream as per V1 but there is no ResumeAsync() method available.
Python 示例使用 NextChunk,但 SendNextChunk 方法受到保護,在 C# 中不可用.
The Python example uses NextChunk but the SendNextChunk method is protected and not available in C#.
在下面的代碼中,如果我讓 UploadVideo() 和 Resume() 完成,但上傳的是整個視頻而不是其余部分,則它們都可以正常工作.
In the code below, both UploadVideo() and Resume() work fine if I leave them to completion but the entire video is uploaded instead of just the remaining parts.
如何使用 google.apis.youtube.v3 恢復中斷的上傳?
How do I resume an interrupted upload using google.apis.youtube.v3?
這是我目前嘗試過的 C# 代碼.
Here is the C# code I have tried so far.
private ResumableUpload<Video> UploadVideo(
YouTubeService youTubeService, Video video, Stream stream, UserCredential userCredentials)
{
var resumableUpload = youTubeService.Videos.Insert(video,
"snippet,status,contentDetails", stream, "video/*");
resumableUpload.OauthToken = userCredentials.Token.AccessToken;
resumableUpload.ChunkSize = 256 * 1024;
resumableUpload.ProgressChanged += resumableUpload_ProgressChanged;
resumableUpload.ResponseReceived += resumableUpload_ResponseReceived;
resumableUpload.UploadAsync();
return resumableUpload;
}
private void Resume(ResumableUpload<Video> resumableUpload)
{
//I tried seeking like V1 but it doesn't work
//if (resumableUpload.ContentStream.CanSeek)
// resumableUpload.ContentStream.Seek(resumableUpload.ContentStream.Position, SeekOrigin.Begin);
resumableUpload.UploadAsync(); // <----This restarts the upload
}
void resumableUpload_ResponseReceived(Video obj)
{
Debug.WriteLine("Video status: {0}", obj.Status.UploadStatus);
}
void resumableUpload_ProgressChanged(IUploadProgress obj)
{
Debug.WriteLine("Position: {0}", (resumableUploadTest == null) ? 0 : resumableUploadTest.ContentStream.Position);
Debug.WriteLine("Status: {0}", obj.Status);
Debug.WriteLine("Bytes sent: {0}", obj.BytesSent);
}
private void button2_Click(object sender, EventArgs e)
{
Resume(resumableUploadTest);
}
任何解決方案/建議/演示或google.apis.youtube.v3"源代碼的鏈接都會非常有幫助.
Any solution/suggestion/demo or a link to the "google.apis.youtube.v3" source code will be very helpful.
提前致謝!
新信息
我仍在努力,我相信 API 還沒有完成.要么那個,要么我錯過了一些簡單的東西.
I'm still working on this and I believe the API simply isn't finished. Either that or I'm missing something simple.
我仍然找不到google.apis.youtube.v3"源代碼,所以我下載了最新的google-api-dotnet-client"源代碼.這包含 YouTube API 使用的 ResumableUpload 類.
I still can't find the "google.apis.youtube.v3" source code so I downloaded the latest "google-api-dotnet-client" source code. This contains the ResumableUpload class used by the YouTube API.
通過跳過 UploadAsync() 方法中的前四行代碼,我成功地繼續上傳.我創建了一個名為 ResumeAsync() 的新方法,它是 UploadAsync() 的副本,其中刪除了前四行初始化代碼.一切正常,上傳從原來的位置恢復并完成.
I managed to successfully continue an upload by skipping the first four lines of code in the UploadAsync() method. I created a new method called ResumeAsync(), a copy of UploadAsync() with the first four lines of initialization code removed. Everything worked and the upload resumed from where it was and completed.
我不想更改 API 中的代碼,所以如果有人知道我應該如何使用它,請告訴我.
I'd rather not be changing code in the API so if anyone knows how I should be using this, let me know.
我會繼續努力,看看能不能解決.
I'll keep plugging away and see if I can work it out.
這是原始的 UploadAsync() 方法和我的 ResumeAsync() hack.
This is the original UploadAsync() method and my ResumeAsync() hack.
public async Task<IUploadProgress> UploadAsync(CancellationToken cancellationToken)
{
try
{
BytesServerReceived = 0;
UpdateProgress(new ResumableUploadProgress(UploadStatus.Starting, 0));
// Check if the stream length is known.
StreamLength = ContentStream.CanSeek ? ContentStream.Length : UnknownSize;
UploadUri = await InitializeUpload(cancellationToken).ConfigureAwait(false);
Logger.Debug("MediaUpload[{0}] - Start uploading...", UploadUri);
using (var callback = new ServerErrorCallback(this))
{
while (!await SendNextChunkAsync(ContentStream, cancellationToken).ConfigureAwait(false))
{
UpdateProgress(new ResumableUploadProgress(UploadStatus.Uploading, BytesServerReceived));
}
UpdateProgress(new ResumableUploadProgress(UploadStatus.Completed, BytesServerReceived));
}
}
catch (TaskCanceledException ex)
{
Logger.Error(ex, "MediaUpload[{0}] - Task was canceled", UploadUri);
UpdateProgress(new ResumableUploadProgress(ex, BytesServerReceived));
throw ex;
}
catch (Exception ex)
{
Logger.Error(ex, "MediaUpload[{0}] - Exception occurred while uploading media", UploadUri);
UpdateProgress(new ResumableUploadProgress(ex, BytesServerReceived));
}
return Progress;
}
public async Task<IUploadProgress> ResumeAsync(CancellationToken cancellationToken)
{
try
{
using (var callback = new ServerErrorCallback(this))
{
while (!await SendNextChunkAsync(ContentStream, cancellationToken).ConfigureAwait(false))
{
UpdateProgress(new ResumableUploadProgress(UploadStatus.Uploading, BytesServerReceived));
}
UpdateProgress(new ResumableUploadProgress(UploadStatus.Completed, BytesServerReceived));
}
}
catch (TaskCanceledException ex)
{
UpdateProgress(new ResumableUploadProgress(ex, BytesServerReceived));
throw ex;
}
catch (Exception ex)
{
UpdateProgress(new ResumableUploadProgress(ex, BytesServerReceived));
}
return Progress;
}
這些是顯示上傳恢復的Fiddler 記錄.
These are the Fiddler records showing the upload resuming.
推薦答案
我已經設法使用反射使其工作,并完全避免了修改 API 的需要.為了完整起見,我將記錄該過程,但不建議這樣做.在可恢復的上傳對象中設置私有屬性不是一個好主意.
I've managed to get this to work using reflection and avoided the need to modify the API at all. For completeness, I'll document the process but it isn't recommended. Setting private properties in the resumable upload object is not a great idea.
當您的可恢復上傳對象在應用程序重啟或重啟后被銷毀時,您仍然可以使用 Google.Apis.YouTube.v3 客戶端庫.
When your resumeable upload object has been destroyed after an application restart or reboot, you can still resume an upload using version "1.8.0.960-rc" of the Google.Apis.YouTube.v3 Client Library.
private static void SetPrivateProperty<T>(Object obj, string propertyName, object value)
{
var propertyInfo = typeof(T).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
if (propertyInfo == null) return;
propertyInfo.SetValue(obj, value, null);
}
private static object GetPrivateProperty<T>(Object obj, string propertyName)
{
if (obj == null) return null;
var propertyInfo = typeof(T).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
return propertyInfo == null ? null : propertyInfo.GetValue(obj, null);
}
您需要在 ProgressChanged 事件期間保存 UploadUri.
You need to save the UploadUri during the ProgressChanged event.
Upload.ResumeUri = GetPrivateProperty<ResumableUpload<Video>>(InsertMediaUpload, "UploadUri") as Uri;
您需要在調用 ResumeAsync 之前設置 UploadUri 和 StreamLength.
You need to set the UploadUri and StreamLength before calling ResumeAsync.
private const long UnknownSize = -1;
SetPrivateProperty<ResumableUpload<Video>>(InsertMediaUpload, "UploadUri", Upload.ResumeUri);
SetPrivateProperty<ResumableUpload<Video>>(InsertMediaUpload, "StreamLength", fileStream.CanSeek ? fileStream.Length : Constants.UnknownSize);
Task = InsertMediaUpload.ResumeAsync(CancellationTokenSource.Token);
這篇關于YouTube C# API V3,如何恢復中斷的上傳?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!