Бот на .NET. Telegram + Google API

от автора

Очень долгое время слушал музыку непосредственно в Telegram. Там и пообщаться можно и проигрыватель довольно удобный. Но рано или поздно — каждый сталкивается с проблемой, когда свой плейлист надоедает и хочется чего-то нового. В YouTube Music есть довольно удобная функция, которая позволяет каждый день довольствоваться новой музыкой. Что я имею ввиду? При включении любой песни, далее проигрывается трек, который похож на предыдущий. Таким образом можно постоянно открывать для себя новые музыкальные горизонты 🙂

В Телеграмме у меня было сохранено более 1000 песен. Я решил написать бота, который будет считывать пересланную музыку из ТГ, создавать плейлист в YouTube и загружать все песни туда. Таким образом и чему-то новому научусь и песни загружу(ну и если кому-то из знакомых понадобятся услуги моего бота, это может сэкономить им время, хотя я мало верю, что кому-то это пригодится, это больше небольшой, учебный проектик).

Для начала нужно зайти в тг, и с помощью этого бота, создать своего:

Здесь нам нужно скопировать токен, чтобы программа могла идентифицировать нашего бота
Здесь нам нужно скопировать токен, чтобы программа могла идентифицировать нашего бота

После этого, я создал проект .NET 5 в Visual Studio 2019. Используя NuGet, а именно, эти 4 библиотеки:

Newtonsoft.Json — является не обязательной, добавил исключительно для удобства. Можно использовать встроенную в .NET:
using System.Text.Json;

Создал класс Brain, который будет управлять всеми жизненными основными процессами бота:

class Brain {  public static ITelegramBotClient Bot { get; set; } =  new TelegramBotClient("token"); // Заменить на свой токен  public static async Task HandleMessageAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) {   Console.WriteLine(JsonConvert.SerializeObject(update));    if (update.Type == Telegram.Bot.Types.Enums.UpdateType.Message)   {     var message = update.Message;     String queryString = "";      if (message.Text != null)     {       if (message.Text.ToLower() == "/start")       {         // Тут можно описать какую-то логику для приветствия, или произвести // инициализацию бота, если такая требуется         await botClient.SendTextMessageAsync(message.Chat, "Добро пожаловать, полосатый");         return;       }        queryString = message.Text;// Если написать название песни текстом, вместо того, // чтобы переслать ее. Это должно тоже работать. Поэтому мы отслеживаем текст, // который присылают боту     }      if (message.Audio != null) //если это музыка, берем имя автора и песни     {       Audio audio = message.Audio;        queryString = audio.Performer;       queryString += " - " + audio.Title;     }         String url = "https://music.youtube.com/search?q=";       queryString = queryString.Replace(" ", "+");       Console.WriteLine(url += queryString);        await botClient.SendTextMessageAsync(message.Chat, url);       return;   } }  public static async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) {   Console.WriteLine(JsonConvert.SerializeObject(exception)); } }

Класс Program и непосредственно сам Main:

class Program  { static void Main(string[] args) {   Console.WriteLine($"Bot has been started: {Brain.Bot.GetMeAsync().Result.FirstName}");    var cts = new CancellationTokenSource();   var cancellationToken = cts.Token;   var receiverOptions = new ReceiverOptions   {     AllowedUpdates = { },   };    Brain.Bot.StartReceiving(       Brain.HandleMessageAsync,       Brain.HandleErrorAsync,       receiverOptions,       cancellationToken   );    Console.ReadLine(); } }

Итак, на данный момент, наш бот уже умеет распознавать текст и готовые песни. После чего он берет их название, преобразовывает в query string, добавляет к стандартному url’у и возвращает готовую ссылку пользователю в ответ. Выглядит это примерно вот так:

Кстати, ему уже сейчас можно пересылать песни огромными пачками, в ответ от присылает столько же ссылок на них 🙂
Это не совсем то, что нам нужно, но мы уже ближе подобрались к решению.

Теперь нам нужно создавать плейлист, и загружать песни туда. Чтобы сделать это необходимо залогиниться в гугл, я буду использовать OAuth2. Прежде всего, я создал приложение в консоли: подключил необходимый инструмент для вызова апи YouTube(YouTube Data API v3) и настроил OAuth2 логин.

Описал класс YTMusicController:

class YTMusicController  {  private static String client_id = "your client id";  private static String client_secret = "your client secret";   internal static UserCredential credential;  private static YouTubeService youTubeService = new YouTubeService(new BaseClientService.Initializer() {   ApiKey = "your api key", // можно получить в приложении гугл консоли   HttpClientInitializer = Brain.credential,   ApplicationName = "YTMusic" });  private static void Reinit()   {     youTubeService = new YouTubeService(new BaseClientService.Initializer()     {       ApiKey = "AIzaSyDLk83ykqHtYOOjDwtvZvSf5S7wOIvGeGY",       HttpClientInitializer = credential,       ApplicationName = "YTMusic"     });   }    public static async Task Login() // функция которая позволяет залогинится с помощью OAuth2   {                                // вызывается один раз при запуске бота     var client_secrets = new ClientSecrets();     client_secrets.ClientId = YTMusicController.client_id;     client_secrets.ClientSecret = YTMusicController.client_secret     credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(       client_secrets,       new[] { YouTubeService.Scope.Youtube },       "user",       CancellationToken.None,       new FileDataStore("YTMusicBrain")       );        Reinit(); // переприсваиваем объект YouTubeService с УЖЕ залогиненным юзером   }      public static async Task CreateNewPlaylist(Chat chatId)   {     Playlist playlist = new Playlist();     playlist.Snippet = new PlaylistSnippet();     var t = Guid.NewGuid().ToString(); // плейлист с случайным имене     playlist.Snippet.Title = t;     playlist.Snippet.Description = "This playlist created automatically";     playlist.Status = new PlaylistStatus();     playlist.Status.PrivacyStatus = "public";     playlist = await youTubeService.Playlists.Insert(playlist, "snippet, status").ExecuteAsync(); // после создания плейлиста я записываю его в мапу которая хранит значение // плейлиста по значению чат     Brain.chat_playlist.Add(chatId.Id, playlist);      public static async Task<SearchResult> Search(String searchQuery)   {     var searchListResult = youTubeService.Search.List("snippet"); // формируем запрос для      searchListResult.Q = searchQuery;                    // для получения указанной песни     searchListResult.MaxResults = 1     var response = await searchListResult.ExecuteAsync();// отправляем запро     return response.Items[0];      public static async Task AddToTestPlaylist(Chat chatId, String searchQuery)   {     Playlist main = Brain.chat_playlist[chatId.Id];     var temp = new PlaylistItem()     var resultOfSearch = await Search(searchQuery); // получаем указанную песн     temp.Snippet = new PlaylistItemSnippet();     temp.Snippet.PlaylistId = main.Id;     temp.Snippet.ResourceId = new ResourceId();     temp.Snippet.ResourceId.Kind = "youtube#video";     temp.Snippet.ResourceId.VideoId = resultOfSearch.Id.VideoId; // создаем новый плейлист, который помещаем в наш уже созданный     await youTubeService.PlaylistItems.Insert(temp, "snippet").ExecuteAsync();     return;   } } 

Добавил команду «/create» через упомянутого выше бота. После ее вызова у нас будет создаваться плейлист в YouTube. Дополним функцию HandleMessageAsync следующим кодом:

if (YTMusicController.credential == null)    { await YTMusicController.Login();  } // ... ..... ... // if (message.Text.ToLower() == "/create")   {     await YTMusicController.CreateNewPlaylist(message.Chat);   }    if ( chat_playlist != null && chat_playlist.ContainsKey(message.Chat.Id))   {     await YTMusicController.AddToTestPlaylist(message.Chat, queryString);   } // если плейлист есть в списке, мы записываем в него найденную песню // иначе мы просто возвращаем ссылку на песню   else   {     String url = "https://music.youtube.com/search?q=";     queryString = queryString.Replace(" ", "+");     Console.WriteLine(url += queryString);      await botClient.SendTextMessageAsync(message.Chat, url);     return;   }

Полный код класса Brain:

class Brain  {  public static ITelegramBotClient Bot { get; set; } = new TelegramBotClient("Api Key");  public static Dictionary<long, Playlist> chat_playlist = new Dictionary<long, Playlist>();  public static async Task HandleMessageAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) {   if (YTMusicController.credential == null)     await YTMusicController.Login();    Console.WriteLine(JsonConvert.SerializeObject(update));    if (update.Type == Telegram.Bot.Types.Enums.UpdateType.Message)   {     var message = update.Message;     String queryString = "";      if (message.Text != null)     {       if (message.Text.ToLower() == "/start")       {         await botClient.SendTextMessageAsync(message.Chat, "Добро пожаловать, полосатый");         return;       }        if (message.Text.ToLower() == "/create")       {         await YTMusicController.CreateNewPlaylist(message.Chat);       }        queryString = message.Text;       return;     }      if (message.Audio != null)     {       Audio audio = message.Audio;        queryString = audio.Performer;       queryString += " - " + audio.Title;     }      if ( chat_playlist != null && chat_playlist.ContainsKey(message.Chat.Id))     {       await YTMusicController.AddToTestPlaylist(message.Chat, queryString);     }     else     {       String url = "https://music.youtube.com/search?q=";       queryString = queryString.Replace(" ", "+");       Console.WriteLine(url += queryString);        await botClient.SendTextMessageAsync(message.Chat, url);       return;     }   } }  public static async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) {   Console.WriteLine(JsonConvert.SerializeObject(exception)); } }

Собственно, готово. Вот как это работает:

  1. Единоразово при запуске бота, выполняется логин.

  2. При вызове команды /create, создается новый плейлист, который записывается по ID чата в коллекцию(до вызова команды /create бот просто возвращает ссылку на песню).

  3. Когда боту присылаешь песню, или название песни, он ищет ее в YouTube, возвращает, и там мы добавляем эту песню в наш плейлист.

Вообще, в идеале, было бы хранить данные плейлистов в какой-нибудь базе данных или на облаке, в крайнем случае, хотя бы записывать в файл(однако, я не заморачивался).

Проект исключительно «for fun», так что не судите строго:)


ссылка на оригинал статьи https://habr.com/ru/post/669488/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *