Как загрузить видео на YouTube с помощью Google.Apis.YouTube.v3 и С#?

Я создал приложение console, используя C#. Который будет upload Video от локального диска до youtube. Я создал новое приложение в google api, используя эту ссылку. Я также установил все необходимые packages с помощью nuget. Когда я запускаю свое приложение, я получаю сообщение об ошибке " Отказано в доступе". Я не могу найти проблему.

Я получаю ошибку в методе 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 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 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?

Любой рабочий пример с использованием С# (console/web)?

Помогите оценить.

Ответ 1

Все кредиты @iedoc за его код и ответ здесь

Основной рабочий пример веб-проекта

Default.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>

Default.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://stackoverflow.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, они просто не работали. Я предполагаю, что это была случайная ошибка.
  • У меня также есть пара MP4, которую я загрузил с Youtube, который не будет загружен обратно, в студии создателя они скажут: "Ошибка загрузки: невозможно обработать файл". Я определил это, пытаясь загрузить их в интерфейс youTube. (не через API)
  • async vs. synchronous вызывал у меня много проблем, которые я просто не понимаю.

Я хотел бы улучшить этот код, чтобы обеспечить фактическое состояние загрузки/обратную связь, но я думаю, что это нужно сделать на стороне клиента. Я не очень хорошо разбираюсь в С#/. NET

ОБНОВЛЕНИЕ вот мой код обратной связи с сервера и клиента - fooobar.com/questions/2294330/...

Ответ 2

Я внес некоторые незначительные изменения в ваш код, лучше всего сначала выполнить ваш первоначальный пример Oauth2. Трудно сказать, почему вы получаете отказ в доступе. Вот что я изменил.

  • "пользователь", я изменил на Environment.UserName таким образом, имя вашего учетного имени будет именем текущего зарегистрированного пользователя.
  • Я изменил местоположение вашего FileDataStore. Я не настолько уверен, что код, который вы использовали, будет работать. Mine сохранит учетные данные в новом каталоге в текущем рабочем каталоге.

Информация о параметре пользователя, который используется только для создания учетных данных в каталоге, представленном в FileDataStore.

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

Мое имя пользователя входа lilaw таким образом вы можете иметь файлы учетных данных для каждого пользователя. Поскольку это консольное приложение, которое не имеет большого значения.

Что вы должны проверить, если это не работает из коробки:

  • Когда вы создали своего клиента на консоли разработчика Google, убедитесь, что он был другим. Вы не можете использовать консольное приложение с учетными данными браузера, и вы не можете использовать API YouTube с учетной записью службы.
  • Помните, что канал 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 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);
        }
    }
}

Как только у вас есть эта работа, здесь есть несколько примеров: загрузить видео

Ответ 3

Следующий пример кода вызывает метод API playlistItems.list для извлечения списка видеороликов, загружаемых в канал, связанный с запросом. Код также вызывает метод channels.list с параметром мины, установленным в true, чтобы получить идентификатор списка воспроизведения, который идентифицирует загруженные каналы.

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