问题描述
我不知道如何在 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,如何恢复中断的上传?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!