/// <summary> /// Retrieves the information about the YouTube video. /// </summary> /// <param name="videoId"></param> /// <param name="cancellationToken"></param> /// <returns></returns> private async Task <bool> GetVideoAsync(string videoId, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(false); } YouTubeService youtubeService = new YouTubeService(new BaseClientService.Initializer() { ApiKey = Settings.Default.YouTubeApiKey, // "AIzaSyBvZfGSa9NUidAMyvT73Kja3ShotaI9VO0", ApplicationName = Settings.Default.YouTubeClientId // "YouTubeClient" }); _log.Info("successfully init youtubeService in GetVideoAsync"); try { string part = "snippet"; string fields = "items(id, snippet(title, description))"; if (_extendedProps) { part = "snippet, statistics, contentDetails"; fields = "items(id, snippet(title, channelTitle, channelId, publishedAt, description, thumbnails), statistics(viewCount, likeCount, dislikeCount), contentDetails(duration))"; } var videosListRequest = youtubeService.Videos.List(part); _log.Info("Got video list in GetVideoAsync()"); // Set the request filters videosListRequest.Id = videoId; videosListRequest.Fields = fields; // Call the videos.list method to retrieve results matching the specified query term. var videosListResponse = await videosListRequest.ExecuteAsync(cancellationToken); _log.Info("Called the videos.list method to retrieve results matching the specified query term. "); // Create the YouTubeSearchResult object from the YouTube Video. YouTubeSearchResult result = YouTubeParser.ParseResult(videosListResponse.Items[0], _parser, _query); await System.Windows.Application.Current.Dispatcher.BeginInvoke( System.Windows.Threading.DispatcherPriority.Normal, new Action(() => { if (!cancellationToken.IsCancellationRequested) { _store.Add(result); } })); return(true); } catch (Exception ex) { _log.Error("Exception in GetVideoAsync", ex); return(false); } finally { youtubeService.Dispose(); } }
public string GetVideoTitle(string videoUrl) { string htmlSource = GetHtmlSource(videoUrl); YouTubeParser parser = new YouTubeParser(htmlSource); return parser.ExtractTitle(); }
public void ExtractTitle_MissingVideoTitleInSource_ThrowsException() { // Arrange YouTubeParser parser = new YouTubeParser(YouTubeParser.VIDEO_START_TAG + YouTubeParser.VIDEO_END_TAG); // Act + Assert parser.ExtractTitle(); }
public void ExtractTitle_MissingStartTagInSource_ThrowsException() { // Arrange string testVideoTitle = "TEST"; YouTubeParser parser = new YouTubeParser(testVideoTitle + YouTubeParser.VIDEO_END_TAG); // Act + Assert parser.ExtractTitle(); }
public void ExtractTitle_MissingEndTagInSource_ThrowsException() { // Arrange string testVideoTitle = "TEST"; YouTubeParser parser = new YouTubeParser(YouTubeParser.VIDEO_START_TAG + testVideoTitle); // Act + Assert parser.ExtractTitle(); }
public void ExtractTitle_ValidHtml_ReturnsCorrectVideoTitle() { // Arrange string expectedVideoTitle = "TEST"; YouTubeParser parser = new YouTubeParser(YouTubeParser.VIDEO_START_TAG + expectedVideoTitle + YouTubeParser.VIDEO_END_TAG); // Act string actualVideoTitle = parser.ExtractTitle(); // Assert Assert.AreEqual(expectedVideoTitle, actualVideoTitle); }
async Task SearchVideoAsync(string videoLink, string query, Random rand, string[] proxies, DownloaderQueue queue) { if (_token.IsCancellationRequested) { return; } int maxRetries = 5; int retry = 0; string response = null; await Task.Delay(TimeSpan.FromMilliseconds(rand.Next(100, 300))); while (retry < maxRetries) { WebProxy proxy = null; string address = proxies[rand.Next(0, proxies.Length)]; if (!address.IsNullOrEmpty()) { proxy = new WebProxy(String.Format("http://{0}", address)) { UseDefaultCredentials = true } } ; response = await queue.Enqueu(Downloader.DownloadTextAsync(videoLink, proxy: proxy, note: String.Format("Requesting {0} from YouTube...", videoLink))); if (response.IsNullOrEmpty()) { retry++; } else { break; } } if (response.IsNullOrEmpty()) { return; } string description = YouTubeParser.ParseVideoPage(response); _observer.OnNext(new VideoDto() { Description = description, Term = query, SourceURL = videoLink }); } }
public void DownloadAsync(string videoUrl, string downloadDirectory) { TransitionToDownloadingState(); string htmlSource = GetHtmlSource(videoUrl); YouTubeParser youtubeParser = new YouTubeParser(htmlSource); string videolink = youtubeParser.ExtractDownloadLink(); string videoFilepath = CreateDestinationFilepath(downloadDirectory, GetVideoTitle(videoUrl)); _videoRepository.DownloadAsync(videolink, videoFilepath); TransitionToIdleState(); }
public async Task SearchListAsync() { DownloaderQueue queue = new DownloaderQueue(_token); try { string[] proxies = new string[] { null }; // File.ReadAllLines("goodproxies.txt"); Random rand = new Random(DateTime.UtcNow.Millisecond); string baseUrl = @"https://www.youtube.com"; string requestUrl = string.Format("{0}/results?search_query={1}", baseUrl, WebUtility.UrlEncode(_term)); while (!_token.IsCancellationRequested && !string.IsNullOrEmpty(requestUrl)) { int maxRetries = 5; int retry = 0; string response = null; await Task.Delay(TimeSpan.FromMilliseconds(rand.Next(0, 1000))); while (retry < maxRetries) { WebProxy proxy = null; string address = proxies[rand.Next(0, proxies.Length)]; if (!address.IsNullOrEmpty()) { proxy = new WebProxy(String.Format("http://{0}", address)) { UseDefaultCredentials = true } } ; response = await queue.Enqueu(Downloader.DownloadTextAsync(requestUrl, proxy: proxy, note: "Requesting webpage from YouTube...")); //await // Downloader.DownloadTextAsync(requestUrl, proxy: proxy, // note: "Requesting webpage from YouTube..."); if (response.IsNullOrEmpty()) { retry++; } else { break; } } if (response.IsNullOrEmpty()) { break; } VideosPageInfo videosPageInfo = YouTubeParser.ParseVideosPage(response); if (videosPageInfo.Links.Count == 0) { break; } await videosPageInfo.Links.Select(link => String.Format("{0}{1}", baseUrl, link)) .Select(link => SearchVideoAsync(link, _term, rand, proxies, queue)) .WhenAll(); if (videosPageInfo.NextPage.IsNullOrEmpty()) { break; } requestUrl = string.Format("{0}{1}", baseUrl, videosPageInfo.NextPage); } } catch (Exception e) { } finally { if (!_tokenSource.IsCancellationRequested) { _tokenSource.Cancel(); } } }
internal void RespondToEvent(Event chatEvent) { #region Bot Logic // Logic for responding to a "PRIVMSG" event if (chatEvent.GetType().Equals(typeof(ChatEvent))) { // Create a reference for the chat data ChatEvent chatData = (ChatEvent)(chatEvent); string message = chatData.ChatMessage; string user = chatData.User; string channelName = chatData.Channel; #region JOIN and PART commands if (message.Equals("!join") && channelName.Equals(Nutbotty.BOTNAME)) { Log.Message(user + " requested " + Nutbotty.BOTNAME + " to join their channel.", true); if (!Channel.ChannelExistsInDB(user)) { Channel channel = new Channel(user); Channel.AddChannelToDB(channel); new TwitchChatRoom(chatConnection, whisperConnection, channel); SendChatMessage(Nutbotty.BOTNAME + " is now available for " + user + ". Type !commands for a list of commands you can use."); } else { SendChatMessage(Nutbotty.BOTNAME + " is already available for " + user + "."); } } if (message.Equals("!part") && channelName.Equals(Nutbotty.BOTNAME)) { Log.Message(user + " requested " + Nutbotty.BOTNAME + " to part their channel.", true); if (Channel.ChannelExistsInDB(user)) { Channel.DeleteChannelFromDB(user); chatConnection.part(user); SendChatMessage("@" + user + ", thank you for using " + Nutbotty.BOTNAME + ".Type !join if you ever want to use " + Nutbotty.BOTNAME + " again."); } else { SendChatMessage(Nutbotty.BOTNAME + " is not in #" + user + "."); } } #endregion #region Generic Commands // Iterate through table rows in database and check if the trigger text matches the message for (int i = 0; i < ChatCommand.CommandCountInDB(); i++) { //Retrieve command from the database and replace the appropriate strings ChatCommand command = ChatCommand.GetCommandFromDBAtRow(i); string responseText = command.ResponseText; responseText = responseText.Replace("$channel", channelName); responseText = responseText.Replace("$user", user); // Check if the command needs to be matched exactly or "loosely" if ((command.MustBeExact && message.Equals(command.TriggerText)) || (!command.MustBeExact && message.Contains(command.TriggerText))) { // Check if the command is universal, or if the command is in the correct channel if (command.IsUniversal || channelName.Equals(command.ChannelName)) { // Check if the user is the subscriber (iff the command is subscriber only) if ((command.SubscriberOnly && chatData.UserIsSubscriber) || !(command.SubscriberOnly)) { // Check if the user is the moderator (iff the command is moderator only) if ((command.ModeratorOnly && chatData.UserIsModerator) || !(command.ModeratorOnly)) { // Check if the user is the broadcaster (iff the command is broadcaster only) if ((command.BroadcasterOnly && chatData.UserIsBroadcaster) || !(command.BroadcasterOnly)) { // Check if the command is whisper only if (command.WhisperResponse) { SendWhisper(user, responseText); } else { SendChatMessage(responseText); } } else { SendWhisper(user, command.TriggerText + " is only available to the broadcaster."); } } else { SendWhisper(user, command.TriggerText + " is only available to moderators."); } } else { SendWhisper(user, command.TriggerText + " is only available to subscribers."); } } } } #endregion #region BLOCKED PHRASE Commands for (int i = 0; i < BlockedPhrase.PhraseCountInDB(); i++) { string phrase = BlockedPhrase.GetPhraseFromDBAtRow(i); if (message.Contains(phrase)) { if (!chatData.UserIsModerator) { SendChatMessageNoAction(".timeout " + user + " 1"); SendWhisper(user, "Your messages have been purged from " + channelName + " for using the phrase \"" + phrase + "\"."); Log.Message(user + " has been timed out from " + channelName + " for using the phrase \"" + phrase + "\".", true); } } } // Add a quote to the QUOTE table if (message.StartsWith("!block ")) { // Parse the quote text data string phrase = message.Substring("!block ".Length); // If the user is a moderator, add the quote to the database, else do nothing if (chatData.UserIsModerator) { // Assume the command has no arguments, then split on space characters bool hasArgs = false; string[] args = message.Split(' '); // If there is at least one argument, continue, otherwise end if if (args.Length > 1) { hasArgs = true; } else { Log.Message("<" + channelName + "> " + user + " attempted to block phrase, but there was not enough arguments.", true); } // Add phrase to database if there were arguments and phrase doesn't already exist in the database if (hasArgs) { if (BlockedPhrase.PhraseExistsInDB(phrase)) { SendChatMessage(user + ", the phrase \"" + phrase + "\" is already blocked."); Log.Message("<" + channelName + "> " + user + " attempted to block a phrase, but it already exists --> " + phrase, true); } else { BlockedPhrase.BlockPhrase(phrase); SendChatMessage(user + " blocked the phrase [" + (BlockedPhrase.PhraseCountInDB() - 1) + "]: " + phrase); Log.Message("<" + channelName + "> " + user + " blocked a phrase: " + phrase, true); } } } else { SendWhisper(user, "!block is only available to moderators"); Log.Message(user + " attempted to block a phrase but is not a moderator --> " + phrase, true); } } // Delete a quote to the QUOTE table by searching the QuoteText column if (message.StartsWith("!unblock ")) { // Parse the quote text data string phrase = message.Substring("!unblock ".Length); // If the user is a moderator, add the quote to the database, else do nothing if (chatData.UserIsModerator) { // Assume the command has no arguments bool hasArgs = false; // Split the command on space characters string[] args = message.Split(' '); // If there is at least one argument, continue, otherwise end if if (args.Length > 1) { hasArgs = true; } else { Log.Message("<" + channelName + "> " + user + " attempted to unblock a phrase, but there was not enough arguments.", true); } // Add quote to database if there were arguments and the quote exists if (hasArgs) { if (BlockedPhrase.PhraseExistsInDB(phrase)) { BlockedPhrase.UnblockPhrase(phrase); SendChatMessage(user + " unblocked a phrase: " + phrase); Log.Message("<" + channelName + "> " + user + " unblocked a phrase: " + phrase, true); } else { SendChatMessage(user + ", that phrase is already unblocked."); Log.Message("<" + channelName + "> " + user + " attempted to block a phrase, but it does not exist --> " + phrase, true); } } } else { SendWhisper(user, "!unblock is only available to moderators"); Log.Message(user + " attempted to unblock a phrase but is not a moderator --> " + phrase, true); } } #endregion #region QUOTE Commands // Pull a random quote from the QUOTES table Regex quoteRgx = new Regex(@"!quote [0-9]*"); if (message.Equals("!quote") || quoteRgx.IsMatch(message)) { // Assume the command has no arguments, then split on space characters string[] args = message.Split(' '); // If there is at least one argument, continue, otherwise end if int ID = -1; if (args.Length <= 1) { ID = RNG.Next(0, Quote.QuoteCountInDB()); Log.Message(user + " requested a random quote from the database.", true); } else { try { ID = Convert.ToInt32(args[1]); Log.Message(user + " requested for quote #" + ID + " from the database.", true); } catch (Exception e) { Log.Message(e.Message, true); } } // Check if the quote ID is positive and <= number of rows in the database table if (ID >= 0 && ID < Quote.QuoteCountInDB()) { SendChatMessage("[" + ID + "] " + Quote.GetQuoteFromDBAtRow(ID).QuoteText); } else { SendWhisper(user, "There are only " + Quote.QuoteCountInDB() + " quotes in the database."); } } // Add a quote to the QUOTE table if (message.StartsWith("!addquote ")) { // Parse the quote text data string quoteText = message.Substring("!addquote ".Length); Quote quote = new Quote(quoteText, channelName, user, DateTime.Now); // If the user is a moderator, add the quote to the database, else do nothing if (chatData.UserIsModerator) { // Assume the command has no arguments, then split on space characters bool hasArgs = false; string[] args = message.Split(' '); // If there is at least one argument, continue, otherwise end if if (args.Length > 1) { hasArgs = true; } else { Log.Message("<" + channelName + "> " + user + " attempted to add quote, but there was not enough arguments.", true); } // Add quote to database if there were arguments and quote doesn't already exist in the database if (hasArgs) { if (Quote.QuoteExistsInDB(quoteText)) { SendChatMessage(user + ", that quote is already in the database."); Log.Message("<" + channelName + "> " + user + " attempted to add quote, but it already exists --> " + quoteText, true); } else { Quote.AddQuoteToDB(quote); SendChatMessage(user + " added quote [" + (Quote.QuoteCountInDB() - 1) + "]: " + quoteText); Log.Message("<" + channelName + "> " + user + " added quote: " + quoteText, true); } } } else { SendWhisper(user, "!addquote is only available to moderators"); Log.Message(user + " attempted to add a quote but is not a moderator --> " + quoteText, true); } } // Delete a quote to the QUOTE table by searching the QuoteText column if (message.StartsWith("!delquote ")) { // Parse the quote text data string quoteText = message.Substring("!delquote ".Length); // If the user is a moderator, add the quote to the database, else do nothing if (chatData.UserIsModerator) { // Assume the command has no arguments bool hasArgs = false; // Split the command on space characters string[] args = message.Split(' '); // If there is at least one argument, continue, otherwise end if if (args.Length > 1) { hasArgs = true; } else { Log.Message("<" + channelName + "> " + user + " attempted to delete a quote, but there was not enough arguments.", true); } // Add quote to database if there were arguments and the quote exists if (hasArgs) { if (Quote.QuoteExistsInDB(quoteText)) { Quote.DeleteQuoteFromDB(quoteText); SendChatMessage(user + " deleted quote: " + quoteText); Log.Message("<" + channelName + "> " + user + " deleted quote: " + quoteText, true); } else { SendChatMessage(user + ", that quote was not found in the database."); Log.Message("<" + channelName + "> " + user + " attempted to deleted quote, but it does not exist --> " + quoteText, true); } } } else { SendWhisper(user, "!delquote is only available to moderators"); Log.Message(user + " attempted to add a quote but is not a moderator --> " + quoteText, true); } } #endregion #region STRAWPOLL Parser if (message.Contains("strawpoll.me/")) { if (StrawpollParser.GetStrawpollInfo(message) == null) { SendChatMessage(user + ", that is not a valid Strawpoll"); } else { SendChatMessage(user + " pasted a Strawpoll ➤ " + StrawpollParser.GetStrawpollInfo(message)); } } #endregion #region YOUTUBE Parser if (message.Contains("youtube.com/") || message.Contains("youtu.be/")) { Console.WriteLine("YouTube Link detected: " + message); if (YouTubeParser.GetYouTubeVideoID(message) != null) { SendChatMessage(user + " pasted a YouTube video ➤ " + YouTubeParser.GetYouTubeInfo(message, YouTubeParser.IS_VIDEO)); } if (YouTubeParser.GetYouTubePlaylistID(message) != null) { SendChatMessage(user + " pasted a YouTube playlist ➤ " + YouTubeParser.GetYouTubeInfo(message, YouTubeParser.IS_PLAYLIST)); } } #endregion #region GUESSING Commands // CeresBot Guesses if (message.Contains(@"Round Started. Type !guess") && user.Equals("ceresbot")) { int seed = RNG.Next(100); // 30% chance of 45 seconds | 65% chance of 46 seconds | 5% chance of 47 seconds int seconds; if (seed < 30) { seconds = 45; } else if (seed < 95) { seconds = 46; } else { seconds = 47; } // if 45-46 seconds, milliseconds between 0-99, else between 0-25 int milliseconds; if (seconds < 47) { milliseconds = RNG.Next(100); } else { milliseconds = RNG.Next(25); } // Make the guess SendChatMessageNoAction("!guess " + seconds + "\"" + milliseconds.ToString("00")); } // Phantoon guesses if (message.Equals("!phantoon")) { int[] rands = new int[2]; string label = null; int total = 0; // Calculate prediction for (int i = 0; i < rands.Length; i++) { rands[i] = RNG.Next(1, 4); total += rands[i]; if (rands[i] == 1) { label = label + " FAST"; } else if (rands[i] == 2) { label = label + " MID"; } else { label = label + " SLOW"; } } // Send chat message if (total <= 2) { SendChatMessage("predicts " + label + ". THE RNG LORDS ARE WITH US PogChamp"); } else if (total > 2 && total <= 3) { SendChatMessage("predicts " + label + ". Praise Jesus BloodTrail"); } else if (total > 3 && total <= 4) { SendChatMessage("predicts " + label + ". Maybe this won't be a reset after all OMGScoots"); } else if (total > 5 && total <= 6) { SendChatMessage("predicts " + label + ". Phantoon please BibleThump"); } else if (total == 6) { SendChatMessage("predicts " + label + ". You m**********r. RESET RESET RESET SwiftRage"); } } // Eyedoor guesses if (message.Equals("!eyedoor")) { int rand = RNG.Next(0, 5); // Send chat message if (rand == 0) { SendChatMessage("predicts... ZERO beams. THE RNG GODS ARE WITH YOU PogChamp"); } else if (rand == 1) { SendChatMessage("predicts... ONE beam. Allelujah! BloodTrail"); } else if (rand == 2) { SendChatMessage("predicts... TWO beams. You're lucky this time OMGScoots"); } else if (rand == 3) { SendChatMessage("predicts... THREE beams. Come on eye door! DansGame"); } else if (rand == 4) { SendChatMessage("predicts... FOUR beams. DAFUQ BITCH?! SwiftRage"); } } #endregion #region OTHER Commands // Show the uptime for the stream. Information is pulled from DecAPI API by Alex Thomassen if (message.Equals("!uptime")) { string uptime = GetUptime(chatData.Channel); SendChatMessage("@" + user + ": " + uptime); Log.Message(user + " checked the uptime for #" + chatData.Channel + ": " + uptime, true); } // Check how many points Nutbotty has on ceresbot if (message.Contains(Nutbotty.BOTNAME) && message.Contains("how many points") && channelName.Equals("oatsngoats")) { SendChatMessageNoAction("!points"); } // Commit sudoku if (message.Equals("!sudoku")) { if (!chatData.UserIsModerator) { SendChatMessageNoAction(".timeout " + user + " 1"); SendChatMessage(user + " committed sudoku."); } } //if (message.Equals("!foosdaraid")) //{ // for (int i = 0; i < 5; i++) // { // SendChatMessage("Foosda Raid ( ͡° ͜ʖ ͡°)"); // } //} //// Block thinking emoji //if (message.Equals("🤔")) //{ // SendChatMessageNoAction(".timeout " + user + " 1"); // SendWhisper(user, "Your messages have been purged from " + channelName + " for using the thinking emoji. Go sit in the corner."); // Log.Message(user + " has been timed out from " + channelName + " for using the thinking emoji. Go sit in the corner.", true); //} //// FAQ //if ((message.Contains("What") || message.Contains("what")) && (message.Contains(" rbo") || message.Contains(" RBO") || message.Contains(" rbo ") || message.Contains(" RBO "))) //{ // SendChatMessage("RBO stand for Reverse Boss Order. It requires beating the four statue bosses in the following order: Ridley, Draygon, Phantoon, Kraid."); //} //if (message.StartsWith("I think") || message.StartsWith("i think")) //{ // SendChatMessage("Nobody care what you think, " + user); //} #endregion } // Logic for responding to an unknown event else { //Log.Message(chatEvent.ToString(), false); } #endregion }
public void Constructor_MissingHtmlSource_ThrowsException() { // Arrange + Act + Assert YouTubeParser parser = new YouTubeParser(null); }