c# - YouTube C# API V3,如何恢复中断的上传?

标签 c# upload google-api-dotnet-client youtube.net-api resume-upload

我不知道如何在 C# YouTube API 的 V3 中恢复中断的上传。

我现有的代码使用 V1 并且工作正常,但我正在切换到 V3。

如果我在不做任何更改的情况下调用 UploadAsync(),它会从头开始。使用 Fiddler,我可以看到 protocol given here未遵循并重新开始上传。

我已尝试按照 V1 设置流中的位置,但没有可用的 ResumeAsync() 方法。

Python 示例使用 NextChunk,但 SendNextChunk 方法 protected 且在 C# 中不可用。

在下面的代码中,如果我让它们完成,则 UploadVideo() 和 Resume() 都可以正常工作,但会上传整个视频,而不仅仅是其余部分。

如何使用 google.apis.youtube.v3 恢复中断的上传?

这是我到目前为止尝试过的 C# 代码。

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”源代码的链接都将非常有帮助。

提前致谢!

编辑:新信息

我仍在努力,我相信 API 还没有完成。要么,要么我遗漏了一些简单的东西。

我仍然找不到“google.apis.youtube.v3”源代码,所以我下载了最新的“google-api-dotnet-client”源代码。这包含 YouTube API 使用的 ResumableUpload 类。

我通过跳过 UploadAsync() 方法中的前四行代码成功地继续上传。我创建了一个名为 ResumeAsync() 的新方法,它是 UploadAsync() 的一个副本,删除了前四行初始化代码。一切正常,上传从原来的位置恢复并完成。

我不想更改 API 中的代码,所以如果有人知道我应该如何使用它,请告诉我。

我会继续加类,看看能不能解决。

这是原始的 UploadAsync() 方法和我的 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 records显示正在恢复上传。

最佳答案

经过深思熟虑,我决定修改 API 代码。我的解决方案保持向后兼容性。

我在下面记录了我的更改,但我不建议使用它们。

在“Google.Apis.Upload”中的 ResumableUpload 类的 UploadAsync() 方法中,我替换了这段代码。

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);

使用此代码

UpdateProgress(new ResumableUploadProgress(
    BytesServerReceived == 0 ? UploadStatus.Starting : UploadStatus.Resuming, BytesServerReceived));
StreamLength = ContentStream.CanSeek ? ContentStream.Length : UnknownSize;
if (UploadUri == null) UploadUri = await InitializeUpload(cancellationToken).ConfigureAwait(false);

我还公开了 UploadUri 和 BytesServerReceived 属性。这允许在 ResumableUpload 对象被销毁或应用程序重启后继续上传。

您只需按照正常方式重新创建 ResumableUpload,设置这两个字段并调用 UploadAsync() 以恢复上传。这两个字段都需要在原始上传过程中保存。

public Uri UploadUri { get; set; }
public long BytesServerReceived { get; set; }

我还在 IUploadProgress 类的 UploadStatus 枚举中添加了“Resuming”。

public enum UploadStatus
{
    /// <summary>
    /// The upload has not started.
    /// </summary>
    NotStarted,

    /// <summary>
    /// The upload is initializing.
    /// </summary>
    Starting,

    /// <summary>
    /// Data is being uploaded.
    /// </summary>
    Uploading,

    /// <summary>
    /// Upload is being resumed.
    /// </summary>
    Resuming,

    /// <summary>
    /// The upload completed successfully.
    /// </summary>
    Completed,

    /// <summary>
    /// The upload failed.
    /// </summary>
    Failed
};

开始上传没有任何变化。

假设 ResumableUpload 对象和流没有被销毁,再次调用 UploadAsync() 以恢复中断的上传。

如果它们已被销毁,则创建新对象并设置 UploadUri 和 BytesServerReceived 属性。这两个属性可以在原始上传期间保存。视频详情和内容流可以正常配置。

即使在重新启动应用程序或重新启动后,这些少量更改也可以恢复上传。我不确定上传过期还有多久,但我会在对真实应用程序进行更多测试后报告。

为了完整起见,这是我一直在使用的测试代码,在上传过程中多次重启应用程序后,它会愉快地恢复中断的上传。恢复和重新启动之间的唯一区别是设置 UploadUri 和 BytesServerReceived 属性。

resumableUploadTest = youTubeService.Videos.Insert(video, "snippet,status,contentDetails", fileStream, "video/*");
if (resume)
{
    resumableUploadTest.UploadUri = Settings.Default.UploadUri;
    resumableUploadTest.BytesServerReceived = Settings.Default.BytesServerReceived;                 
}                                               
resumableUploadTest.ChunkSize = ResumableUpload<Video>.MinimumChunkSize;
resumableUploadTest.ProgressChanged += resumableUpload_ProgressChanged;
resumableUploadTest.UploadAsync();

我希望这对某人有所帮助。我花了比预期更长的时间来解决这个问题,我仍然希望我错过了一些简单的事情。我花了很长时间试图添加我自己的错误处理程序,但 API 会为您完成所有这些工作。 API 确实可以从轻微的短时间中断中恢复,但不能从应用程序重新启动、重新启动或长时间中断中恢复。

干杯。米克。

关于c# - YouTube C# API V3,如何恢复中断的上传?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21321878/

相关文章:

c# - Entity Framework - 外键组件......不是类型的声明属性

grails - 在grails中上传PDF

c# - 将 Google API 离线访问添加到 .NET Core 应用程序

c# - MicrosoftAppId : '' is unauthorized to post to connector 的安全 token

c# - 如何使用c#获取gridview中的特定数据?

c# - Web.config 转换不转换 VS 2017

spring - 此应用程序没有明确的映射/错误

c# - 将视频上传到YouTube时出错

c# - Google Drive SDK System.Net.Http.Primitives 版本 1.5.0.0 而不是 2.1.10.0

c# - 创建 Google 日历事件后获取事件 ID C#