如何使用 Google.Apis.YouTube.v3 和 C# 将视频上传到 youtube?

Posted

技术标签:

【中文标题】如何使用 Google.Apis.YouTube.v3 和 C# 将视频上传到 youtube?【英文标题】:How to upload Video to youtube using Google.Apis.YouTube.v3 and C#? 【发布时间】:2017-11-19 11:43:34 【问题描述】:

我使用C# 创建了console 应用程序。 它将upload Video 从本地驱动器到youtube。 我使用this link 在google api 中创建了新应用程序。 我还使用nuget 安装了所有必需的packages。 当我运行我的应用程序时,出现“Access Denied”错误,我无法找到问题。

Task Run() 方法出现错误。

using System;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;

namespace Google.Apis.YouTube.Samples

  /// <summary>
  /// YouTube Data API v3 sample: create a playlist.
  /// Relies on the Google APIs Client Library for .NET, v1.7.0 or higher.
  /// See https://developers.google.com/api-client-library/dotnet/get_started
  /// </summary>
  internal class PlaylistUpdates
  
    [STAThread]
    static void Main(string[] args)
    
      Console.WriteLine("YouTube Data API: Playlist Updates");
      Console.WriteLine("==================================");

      try
      
        new PlaylistUpdates().Run().Wait();
      
      catch (AggregateException ex)
      
        foreach (var e in ex.InnerExceptions)
        
          Console.WriteLine("Error: " + e.Message);
        
      

      Console.WriteLine("Press any key to continue...");
      Console.ReadKey();
    

    private async Task Run()
    
      UserCredential credential;
      using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
      
        credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
            GoogleClientSecrets.Load(stream).Secrets,
            // This OAuth 2.0 access scope allows for full read/write access to the
            // authenticated user's account.
            new[]  YouTubeService.Scope.Youtube ,
            "user",
            CancellationToken.None,
            new FileDataStore(this.GetType().ToString())
        );
      

      var youtubeService = new YouTubeService(new BaseClientService.Initializer()
      
        HttpClientInitializer = credential,
        ApplicationName = this.GetType().ToString()
      );

      // Create a new, private playlist in the authorized user's channel.
      var newPlaylist = new Playlist();
      newPlaylist.Snippet = new PlaylistSnippet();
      newPlaylist.Snippet.Title = "Test Playlist";
      newPlaylist.Snippet.Description = "A playlist created with the YouTube API v3";
      newPlaylist.Status = new PlaylistStatus();
      newPlaylist.Status.PrivacyStatus = "public";
      newPlaylist = await youtubeService.Playlists.Insert(newPlaylist, "snippet,status").ExecuteAsync();

      // Add a video to the newly created playlist.
      var newPlaylistItem = new PlaylistItem();
      newPlaylistItem.Snippet = new PlaylistItemSnippet();
      newPlaylistItem.Snippet.PlaylistId = newPlaylist.Id;
      newPlaylistItem.Snippet.ResourceId = new ResourceId();
      newPlaylistItem.Snippet.ResourceId.Kind = "youtube#video";
      newPlaylistItem.Snippet.ResourceId.VideoId = "GNRMeaz6QRI";
      newPlaylistItem = await youtubeService.PlaylistItems.Insert(newPlaylistItem, "snippet").ExecuteAsync();

      Console.WriteLine("Playlist item id 0 was added to playlist id 1.", newPlaylistItem.Id, newPlaylist.Id);
    
  

我是否需要将 'user' 参数传递给 gmail 用户名?

任何使用 C#(控制台/Web)的工作示例?

帮助表示赞赏。

【问题讨论】:

@Chad 那么到底有什么问题呢?失败在哪里?相同的“拒绝访问”? 我收到Inner Exception 1: TokenResponseException: Error:"invalid_client", Description:"Unauthorized", Uri:"" 错误,请参阅我的帖子***.com/questions/49364545/… 我一遍又一遍地看到相同的代码示例和问题,但没有答案。我想知道 .NET 库是否可以正常工作。我已经用了一个多星期了。 @Chad 我刚刚尝试过,对我来说效果很好(不是所有的东西,只是授权部分)。所以这就是为什么我要问你到底哪里有错误。在哪条线上?授权还是以后? Task Run()我的代码执行到credential = await GoogleWebAuthorizationBroker.AuthorizeAsync()的行/方法 @Chad 您的错误表明您的客户端 id\secret 存在一些问题。尝试直接初始化它们:AuthorizeAsync(new ClientSecrets ClientId = "your id", ClientSecret = "secret"...)。使用此页面中的 OAuth2.0 凭据:console.developers.google.com/apis/credentials。修复该问题后 - 运行代码时应打开 Web 浏览器页面。您应该在浏览器中授权此应用程序(登录到 gmail 帐户等)。之后它应该可以正常工作了。 【参考方案1】:

感谢@iedoc 他的code and answer here

一个基本的工作 Web 项目示例

默认.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>testing</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <p><asp:TextBox runat="server" ID="videoName" placeholder="Video Title" /></p>
        <p><asp:TextBox runat="server" ID="videoDesc" placeholder="Video Description" /></p>
        <p><asp:FileUpload ID="videoUpload" runat="server" /></p>
        <p><asp:Button id="saveDetails" Text="Update Chapel Group" runat="server" OnClick="saveDetails_click" /></p>
    </div>
    </form>
</body>
</html>

默认.aspx.cs

using System;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Responses;

public partial class _Default : System.Web.UI.Page

    string vID = "none";
    public void Page_Load(object sender, EventArgs e)
    

    
    protected void saveDetails_click(object sender, EventArgs e)
    
        if (Path.GetFileName(videoUpload.PostedFile.FileName) != "")
        
            YouTubeUtilities ytU = new YouTubeUtilities("REFRESH", "SECRET", "CLIENT_ID"); // pass in your API codes here

            using (var fileStream = videoUpload.PostedFile.InputStream) // the selected post file
            
                vID = ytU.UploadVideo(fileStream,videoName.Text,videoDesc.Text,"22",false);
            
            Response.Write(vID);
        

    

public class YouTubeUtilities

    /*
     Instructions to get refresh token:
     * https://***.com/questions/5850287/youtube-api-single-user-scenario-with-oauth-uploading-videos/8876027#8876027
     * 
     * When getting client_id and client_secret, use installed application, other (this will make the token a long term token)
     */
    private String CLIENT_ID  get; set; 
    private String CLIENT_SECRET  get; set; 
    private String REFRESH_TOKEN  get; set; 

    private String UploadedVideoId  get; set; 

    private YouTubeService youtube;

    public YouTubeUtilities(String refresh_token, String client_secret, String client_id)
    
        CLIENT_ID = client_id;
        CLIENT_SECRET = client_secret;
        REFRESH_TOKEN = refresh_token;

        youtube = BuildService();
    

    private YouTubeService BuildService()
    
        ClientSecrets secrets = new ClientSecrets()
        
            ClientId = CLIENT_ID,
            ClientSecret = CLIENT_SECRET
        ;

        var token = new TokenResponse  RefreshToken = REFRESH_TOKEN ;
        var credentials = new UserCredential(new GoogleAuthorizationCodeFlow(
            new GoogleAuthorizationCodeFlow.Initializer
            
                ClientSecrets = secrets
            ),
            "user",
            token);

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

        //service.HttpClient.Timeout = TimeSpan.FromSeconds(360); // Choose a timeout to your liking
        return service;
    

    public String UploadVideo(Stream stream, String title, String desc, String categoryId, Boolean isPublic)
    
        var video = new Video();
        video.Snippet = new VideoSnippet();
        video.Snippet.Title = title;
        video.Snippet.Description = desc;
        video.Snippet.CategoryId = categoryId; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
        video.Status = new VideoStatus();
        video.Status.PrivacyStatus = isPublic ? "public" : "unlisted"; // "private" or "public" or unlisted

        //var videosInsertRequest = youtube.Videos.Insert(video, "snippet,status", stream, "video/*");
        var videosInsertRequest = youtube.Videos.Insert(video, "snippet,status", stream, "video/*");
        videosInsertRequest.ProgressChanged += insertRequest_ProgressChanged;
        videosInsertRequest.ResponseReceived += insertRequest_ResponseReceived;

        videosInsertRequest.Upload();

        return UploadedVideoId;
    

    void insertRequest_ResponseReceived(Video video)
    
        UploadedVideoId = video.Id;
        // video.ID gives you the ID of the Youtube video.
        // you can access the video from
        // http://www.youtube.com/watch?v=video.ID
    

    void insertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
    
        // You can handle several status messages here.
        switch (progress.Status)
        
            case UploadStatus.Failed:
                UploadedVideoId = "FAILED";
                break;
            case UploadStatus.Completed:
                break;
            default:
                break;
        
    

我讨厌 .NET,我已经为此奋斗了好几个星期。我遇到的一些问题;

    一对错误的 API 密钥,他们只是没有工作。我猜这是一个随机错误。 我还有一些从 Youtube 下载的 MP4 不会上传回来,在创作者工作室中他们会说“上传失败:无法处理文件”我通过尝试在 youtube 界面上传它们来确定这一点。 (不通过 API) 异步与同步给我带来了许多我不明白的问题。

我想改进此代码以提供实际的上传状态/反馈,但我认为这需要在客户端完成。我不太擅长 C#/.NET

更新这是我通过服务器和客户端的反馈代码 - https://***.com/a/49516167/3790921

【讨论】:

这并没有真正回答这个问题,因为它是一个 Web 解决方案,他说他正在使用控制台应用程序。更不用说这个用于上传视频而不插入播放列表的代码你认为你不应该解决这个问题吗? 他说“任何使用 C# (console/web) 的工作示例?” - 这是一个有效的网络示例 我很好奇你为什么要加赏金呢?是因为您的解决方案不起作用吗?如果是这样,您应该尝试我的,它适用于控制台应用程序。你知道你不能靠自己的答案获得赏金吗? 我添加了赏金,因为我遇到了同样的问题......很多人似乎都遇到了问题,但没有答案。赏金是在我为此工作 2 周后添加的,并且在我发布此答案前将近一周。我终于能够回答我自己的问题,因为 Google/DuckDuckGo 不容易找到的另一个 SO 答案。事实上,我对此的最新修订更加简单。 (每个人都有一个控制台应用程序,因为这就是 Google 提供的示例代码)【参考方案2】:

以下代码示例调用 API 的 playlistItems.list 方法来检索上传到与请求关联的频道的视频列表。该代码还调用了将 mine 参数设置为 true 的 channels.list 方法来检索标识频道上传视频的播放列表 ID。

using System;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;

namespace Google.Apis.YouTube.Samples

  /// <summary>
  /// YouTube Data API v3 sample: retrieve my uploads.
  /// Relies on the Google APIs Client Library for .NET, v1.7.0 or higher.
  /// See https://developers.google.com/api-client-library/dotnet/get_started
  /// </summary>
  internal class MyUploads
  
    [STAThread]
    static void Main(string[] args)
    
      Console.WriteLine("YouTube Data API: My Uploads");
      Console.WriteLine("============================");

      try
      
        new MyUploads().Run().Wait();
      
      catch (AggregateException ex)
      
        foreach (var e in ex.InnerExceptions)
        
          Console.WriteLine("Error: " + e.Message);
        
      

      Console.WriteLine("Press any key to continue...");
      Console.ReadKey();
    

    private async Task Run()
    
      UserCredential credential;
      using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
      
        credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
            GoogleClientSecrets.Load(stream).Secrets,
            // This OAuth 2.0 access scope allows for read-only access to the authenticated 
            // user's account, but not other types of account access.
            new[]  YouTubeService.Scope.YoutubeReadonly ,
            "user",
            CancellationToken.None,
            new FileDataStore(this.GetType().ToString())
        );
      

      var youtubeService = new YouTubeService(new BaseClientService.Initializer()
      
        HttpClientInitializer = credential,
        ApplicationName = this.GetType().ToString()
      );

      var channelsListRequest = youtubeService.Channels.List("contentDetails");
      channelsListRequest.Mine = true;

      // Retrieve the contentDetails part of the channel resource for the authenticated user's channel.
      var channelsListResponse = await channelsListRequest.ExecuteAsync();

      foreach (var channel in channelsListResponse.Items)
      
        // From the API response, extract the playlist ID that identifies the list
        // of videos uploaded to the authenticated user's channel.
        var uploadsListId = channel.ContentDetails.RelatedPlaylists.Uploads;

        Console.WriteLine("Videos in list 0", uploadsListId);

        var nextPageToken = "";
        while (nextPageToken != null)
        
          var playlistItemsListRequest = youtubeService.PlaylistItems.List("snippet");
          playlistItemsListRequest.PlaylistId = uploadsListId;
          playlistItemsListRequest.MaxResults = 50;
          playlistItemsListRequest.PageToken = nextPageToken;

          // Retrieve the list of videos uploaded to the authenticated user's channel.
          var playlistItemsListResponse = await playlistItemsListRequest.ExecuteAsync();

          foreach (var playlistItem in playlistItemsListResponse.Items)
          
            // Print information about each video.
            Console.WriteLine("0 (1)", playlistItem.Snippet.Title, playlistItem.Snippet.ResourceId.VideoId);
          

          nextPageToken = playlistItemsListResponse.NextPageToken;
        
      
    
  

【讨论】:

问题是关于插入一个播放列表而不选择一个这不回答这个问题。【参考方案3】:

我对您的代码做了一些小改动,最好先让您最初的 Oauth2 示例工作。很难说出为什么您的访问被拒绝。这是我所做的更改。

    “用户”我已更改为 Environment.UserName 这样您的凭据名称将是当前登录用户的名称。 我已经更改了您的 FileDataStore 的位置 我不太确定您使用的代码是否可以正常工作。我的会将凭据存储在当前工作目录的新目录中。

有关用户参数的信息,它仅用于在提交给 FileDataStore 的目录中创建凭据。

Google.Apis.Auth.OAuth2.Responses.TokenResponse-lilaw

我的登录用户名是lilaw,这样您就可以拥有每个用户的凭据文件。因为这是一个控制台应用程序,并不重要。

如果这不能开箱即用,您应该检查什么:

    当您在 Google 开发者控制台上创建您的客户端时,请确保它是其他类型的。您不能使用带有浏览器凭据的控制台应用程序,也不能使用带有服务帐户的 YouTube API。 请记住,YouTube API 频道基于,因此当您登录时选择一个频道,您将只能访问该频道。

提示:如果您想注销当前用户或强制其重新登录。只需将 Environment.UserName 更改为其他内容,它将强制它再次登录

我已经测试了这段代码它可以工作:

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace TestYoutube

    class Program
    
        [STAThread]
        static void Main(string[] args)
        
            Console.WriteLine("YouTube Data API: Playlist Updates");
            Console.WriteLine("==================================");

            try
            
                new Program().Run().Wait();
            
            catch (AggregateException ex)
            
                foreach (var e in ex.InnerExceptions)
                
                    Console.WriteLine("Error: " + e.Message);
                
            

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        

        private async Task Run()
        
            UserCredential credential;
            using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
            
                credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    new[]  YouTubeService.Scope.Youtube ,
                    Environment.UserName,
                    CancellationToken.None,
                    new FileDataStore($"Directory.GetCurrentDirectory()/credentials")
                );
            

            var youtubeService = new YouTubeService(new BaseClientService.Initializer()
            
                HttpClientInitializer = credential,
                ApplicationName = this.GetType().ToString()
            );

            // Create a new, private playlist in the authorized user's channel.
            var newPlaylist = new Playlist
            
                Snippet = new PlaylistSnippet
                
                    Title = "Test Playlist",
                    Description = "A playlist created with the YouTube API v3"
                ,
                Status = new PlaylistStatus PrivacyStatus = "public"
            ;
            newPlaylist = await youtubeService.Playlists.Insert(newPlaylist, "snippet,status").ExecuteAsync();

            // Add a video to the newly created playlist.
            var newPlaylistItem = new PlaylistItem
            
                Snippet = new PlaylistItemSnippet
                
                    PlaylistId = newPlaylist.Id,
                    ResourceId = new ResourceId
                    
                        Kind = "youtube#video",
                        VideoId = "GNRMeaz6QRI"
                    
                
            ;
            newPlaylistItem = await youtubeService.PlaylistItems.Insert(newPlaylistItem, "snippet").ExecuteAsync();

            Console.WriteLine("Playlist item id 0 was added to playlist id 1.", newPlaylistItem.Id, newPlaylist.Id);
        
    

一旦你有了这个工作,这里有几个例子,一个是upload video

【讨论】:

以上是关于如何使用 Google.Apis.YouTube.v3 和 C# 将视频上传到 youtube?的主要内容,如果未能解决你的问题,请参考以下文章

[精选] Mysql分表与分库如何拆分,如何设计,如何使用

如果加入条件,我该如何解决。如果使用字符串连接,我如何使用

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等