PageRenderTime 83ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/wormy/Modules/YouTubeModule.cs

https://gitlab.com/SirCmpwn/wormy
C# | 174 lines | 164 code | 9 blank | 1 comment | 40 complexity | ca6401689410b452369c81f4272a006b MD5 | raw file
  1. using System;
  2. using System.Net;
  3. using System.IO;
  4. using System.Xml.Linq;
  5. using System.Linq;
  6. using System.Globalization;
  7. using ChatSharp.Events;
  8. using System.Threading.Tasks;
  9. using Newtonsoft.Json.Linq;
  10. using System.Xml;
  11. namespace wormy.Modules
  12. {
  13. // TODO: Add some stuff to ChatSharp to make formatting colored messages less painful
  14. [Depends(typeof(GoogleModule))]
  15. [Depends(typeof(LinksModule))]
  16. public class YouTubeModule : Module
  17. {
  18. public override string Name { get { return "youtube"; } }
  19. public override string Description { get { return "Searches YouTube videos and handles YouTube links."; } }
  20. public YouTubeModule(NetworkManager network) : base(network)
  21. {
  22. if (string.IsNullOrEmpty(Program.Configuration.GoogleAPIKey))
  23. return;
  24. RegisterUserCommand("youtube", HandleCommand, "youtube [terms]: Searches YouTube for [terms] and shows information about the first result.");
  25. RegisterUserCommand("yt", HandleCommand);
  26. network.ModulesLoaded += (sender, e) => GetModule<LinksModule>().RegisterHostHandler("www.youtube.com", HandleLink);
  27. network.ModulesLoaded += (sender, e) => GetModule<LinksModule>().RegisterHostHandler("youtube.com", HandleLink);
  28. network.ModulesLoaded += (sender, e) => GetModule<LinksModule>().RegisterHostHandler("youtu.be", HandleLink);
  29. }
  30. void HandleLink(Uri uri, PrivateMessageEventArgs e)
  31. {
  32. HandleCommand(new[] { uri.ToString() }, e);
  33. }
  34. void HandleCommand(string[] arguments, PrivateMessageEventArgs e)
  35. {
  36. Task.Factory.StartNew(() =>
  37. {
  38. if (arguments.Length == 0)
  39. return;
  40. string vid;
  41. if (arguments.Length != 1 || (!arguments[0].StartsWith("http://") && !arguments[0].StartsWith("https://")))
  42. {
  43. var results = GoogleModule.DoGoogleSearch("site:youtube.com " + string.Join(" ", arguments));
  44. if (results.Count == 0)
  45. {
  46. Respond(e, "No results found.");
  47. return;
  48. }
  49. else
  50. vid = results.First().Substring(results.First().LastIndexOf("http://"));
  51. }
  52. else
  53. vid = arguments[0];
  54. if (!vid.StartsWith("http://") && !vid.StartsWith("https://"))
  55. vid = "http://" + vid;
  56. if (Uri.IsWellFormedUriString(vid, UriKind.Absolute))
  57. {
  58. Uri uri = new Uri(vid);
  59. if (uri.Host == "youtu.be" || uri.Host == "www.youtu.be")
  60. vid = uri.LocalPath.Trim('/');
  61. else
  62. {
  63. var query = System.Web.HttpUtility.ParseQueryString(uri.Query);
  64. vid = query["v"];
  65. }
  66. if (vid == null)
  67. {
  68. Respond(e, "Video not found.");
  69. return;
  70. }
  71. }
  72. var video = GetYoutubeVideo(vid);
  73. if (video == null)
  74. {
  75. Respond(e, "Video not found.");
  76. return;
  77. }
  78. string partOne = "\"\u0002" + video.Title + "\u000f\" [" + video.Duration.ToString("m\\:ss")
  79. + "] (\u000312" + video.Author + "\u000f)\u000303 " + (video.HD ? "HD" : "SD");
  80. string partTwo = video.Views.ToString("N0", CultureInfo.InvariantCulture) + " views";
  81. if (video.RatingsEnabled)
  82. {
  83. partTwo += ", " + "(+\u000303" + video.Likes.ToString("N0", CultureInfo.InvariantCulture)
  84. + "\u000f|-\u000304" + video.Dislikes.ToString("N0", CultureInfo.InvariantCulture) + "\u000f) [" + video.Stars + "]";
  85. }
  86. if (video.RegionLocked | !video.CommentsEnabled || !video.RatingsEnabled)
  87. {
  88. partTwo += " ";
  89. if (video.RegionLocked)
  90. partTwo += "\u000304Region locked\u000f, ";
  91. if (!video.CommentsEnabled)
  92. partTwo += "\u000304Comments disabled\u000f, ";
  93. if (!video.RatingsEnabled)
  94. partTwo += "\u000304Ratings disabled\u000f, ";
  95. partTwo = partTwo.Remove(partTwo.Length - 3);
  96. }
  97. if (partOne.Length < partTwo.Length)
  98. partOne += "\u000f " + video.VideoUri.ToString();
  99. else
  100. partTwo += "\u000f " + video.VideoUri.ToString();
  101. Respond(e, partOne);
  102. Respond(e, partTwo);
  103. });
  104. }
  105. class Video
  106. {
  107. public string Title, Author;
  108. public int Views, Likes, Dislikes;
  109. public TimeSpan Duration;
  110. public bool RegionLocked, HD, CommentsEnabled, RatingsEnabled;
  111. public string Stars;
  112. public Uri VideoUri;
  113. }
  114. private Video GetYoutubeVideo(string vid)
  115. {
  116. try
  117. {
  118. WebClient client = new WebClient();
  119. var sr = new StreamReader(client.OpenRead(string.Format(
  120. "https://www.googleapis.com/youtube/v3/videos?part=id%2Csnippet%2Cstatistics%2CcontentDetails%2Cstatus%2Clocalizations&id={0}&key={1}",
  121. Uri.EscapeUriString(vid), Uri.EscapeUriString(Program.Configuration.GoogleAPIKey))));
  122. string json = sr.ReadToEnd();
  123. JObject j = JObject.Parse(json);
  124. if (j["items"].Count() == 0)
  125. return null;
  126. dynamic i = j["items"][0];
  127. Video video = new Video();
  128. video.Title = i.snippet.title;
  129. video.Author = i.snippet.channelTitle;
  130. video.CommentsEnabled = true; // NOTE: YouTube has removed this from their API, assholes
  131. video.RatingsEnabled = i.status.publicStatsViewable;
  132. if (video.RatingsEnabled)
  133. {
  134. video.Likes = i.statistics.likeCount;
  135. video.Dislikes = i.statistics.dislikeCount;
  136. double average;
  137. if (video.Likes + video.Dislikes == 0) average = 1;
  138. else average = (double)video.Likes / (video.Likes + video.Dislikes);
  139. video.Stars = "\u000303";
  140. int starCount = (int)Math.Round(average * 5);
  141. for (int k = 0; k < 5; k++)
  142. {
  143. if (k < starCount)
  144. video.Stars += "★";
  145. else if (k == starCount)
  146. video.Stars += "\u000315☆";
  147. else
  148. video.Stars += "☆";
  149. }
  150. video.Stars += "\u000f";
  151. }
  152. video.Views = i.statistics.viewCount;
  153. video.Duration = XmlConvert.ToTimeSpan(i["contentDetails"]["duration"].Value);
  154. video.RegionLocked = i.contentDetails["regionRestriction"] != null;
  155. video.VideoUri = new Uri("http://youtu.be/" + vid);
  156. video.HD = i.contentDetails.definition == "hd";
  157. return video;
  158. }
  159. catch
  160. {
  161. return null;
  162. }
  163. }
  164. }
  165. }