The easy to use and full featured Irc Bot everyone is talking about!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Url_Parsing.cs 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. using System.Web;
  9. using Combot.IRCServices.Messaging;
  10. using Newtonsoft.Json;
  11. using Newtonsoft.Json.Linq;
  12. namespace Combot.Modules.Plugins
  13. {
  14. public class Url_Parsing : Module
  15. {
  16. private const string YOUTUBE_URL = "(((youtube.*(v=|/v/))|(youtu\\.be/))(?<ID>[-_a-zA-Z0-9]+))";
  17. public override void Initialize()
  18. {
  19. Bot.IRC.Message.ChannelMessageReceivedEvent += HandleChannelMessage;
  20. }
  21. public void HandleChannelMessage(object sender, ChannelMessage message)
  22. {
  23. Regex urlRegex = new Regex("(https?)://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?");
  24. if (Enabled
  25. && !Bot.ServerConfig.ChannelBlacklist.Contains(message.Channel)
  26. && !Bot.ServerConfig.NickBlacklist.Contains(message.Sender.Nickname)
  27. && !ChannelBlacklist.Contains(message.Channel)
  28. && !NickBlacklist.Contains(message.Sender.Nickname)
  29. && !Bot.IsCommand(message.Message))
  30. {
  31. if (urlRegex.IsMatch(message.Message))
  32. {
  33. // Check to see if it's being spammed
  34. if (Bot.SpamCheck(Bot.IRC.Channels.Find(chan => chan.Name == message.Channel), message.Sender, this, new Command() { Name = string.Format( "{0} Commands", Name) }))
  35. {
  36. MatchCollection urlMatches = urlRegex.Matches(message.Message);
  37. for (int i = 0; i < urlMatches.Count; i++)
  38. {
  39. Match urlMatch = urlMatches[i];
  40. Uri url = new Uri(urlMatch.Value);
  41. HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
  42. webRequest.Method = "HEAD";
  43. webRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
  44. ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
  45. ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
  46. try
  47. {
  48. using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
  49. {
  50. int code = (int)webResponse.StatusCode;
  51. if (code == 200)
  52. {
  53. string contentType = webResponse.ContentType.Split('/')[0];
  54. long contentLength = webResponse.ContentLength;
  55. switch (contentType)
  56. {
  57. case "image":
  58. Bot.IRC.Command.SendPrivateMessage(message.Channel, string.Format("[{0}] Size: {1}", webResponse.ContentType, ToFileSize(contentLength)));
  59. break;
  60. case "video":
  61. Bot.IRC.Command.SendPrivateMessage(message.Channel, string.Format("[Video] Type: {0} | Size: {1}", webResponse.ContentType.Split('/')[1], ToFileSize(contentLength)));
  62. break;
  63. case "application":
  64. Bot.IRC.Command.SendPrivateMessage(message.Channel, string.Format("[Application] Type: {0} | Size: {1}", webResponse.ContentType.Split('/')[1], ToFileSize(contentLength)));
  65. break;
  66. case "audio":
  67. Bot.IRC.Command.SendPrivateMessage(message.Channel, string.Format("[Audio] Type: {0} | Size: {1}", webResponse.ContentType.Split('/')[1], ToFileSize(contentLength)));
  68. break;
  69. default:
  70. Regex ytRegex = new Regex(YOUTUBE_URL);
  71. if (ytRegex.IsMatch(urlMatch.ToString()))
  72. {
  73. Match ytMatch = ytRegex.Match(urlMatch.ToString());
  74. string youtubeMessage = GetYoutubeDescription(ytMatch.Groups["ID"].Value);
  75. Regex ytTitle = new Regex(YOUTUBE_URL);
  76. if (ytTitle.IsMatch(youtubeMessage))
  77. {
  78. youtubeMessage = ytTitle.Replace(youtubeMessage, string.Empty);
  79. }
  80. Bot.IRC.Command.SendPrivateMessage(message.Channel, youtubeMessage);
  81. }
  82. else
  83. {
  84. ParseTitle(message, urlMatch.ToString());
  85. }
  86. break;
  87. }
  88. }
  89. else
  90. {
  91. Bot.IRC.Command.SendPrivateMessage(message.Channel, string.Format("[URL] Returned Status Code \u0002{0}\u0002 ({1})", code, url.Host));
  92. }
  93. }
  94. }
  95. catch (WebException ex)
  96. {
  97. if (ex.Response != null)
  98. {
  99. int code = (int)((HttpWebResponse)ex.Response).StatusCode;
  100. Bot.IRC.Command.SendPrivateMessage(message.Channel, string.Format("[URL] Response Code: \u0002{0}\u0002 ({1})", code, url.Host));
  101. }
  102. }
  103. catch (OutOfMemoryException ex)
  104. {
  105. Bot.IRC.Command.SendPrivateMessage(message.Channel, string.Format("[URL] \u0002Site content was too large\u0002 ({0})", url.Host));
  106. }
  107. }
  108. }
  109. }
  110. }
  111. }
  112. public void ParseTitle(ChannelMessage message, string urlString)
  113. {
  114. string title = string.Empty;
  115. bool startTagFound = false;
  116. Uri url = new Uri(urlString);
  117. HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(urlString);
  118. StreamReader streamReader = new StreamReader(req.GetResponse().GetResponseStream());
  119. Char[] buf = new Char[256];
  120. int count = streamReader.Read(buf, 0, 256);
  121. var stopwatch = Stopwatch.StartNew();
  122. TimeSpan timeout = new TimeSpan(0, 0, 15);
  123. while (count > 0 && stopwatch.Elapsed < timeout)
  124. {
  125. String outputData = new String(buf, 0, count);
  126. if (!startTagFound)
  127. {
  128. // check for a full match
  129. Match fullMatch = Regex.Match(outputData, @"\<title\b[^>]*\>\s*(?<Title>[\s\S]*?)\</title\>", RegexOptions.IgnoreCase);
  130. if (fullMatch.Success)
  131. {
  132. title = fullMatch.Groups["Title"].Value;
  133. break;
  134. }
  135. }
  136. string pattern = string.Empty;
  137. if (startTagFound)
  138. {
  139. pattern = @"^(?<Title>[\s\S]*?)\</title\>";
  140. Match match = Regex.Match(outputData, pattern, RegexOptions.IgnoreCase);
  141. if (match.Success)
  142. {
  143. title += match.Groups["Title"].Value;
  144. break;
  145. }
  146. title += outputData;
  147. }
  148. else
  149. {
  150. pattern = @"\<title\b[^>]*\>\s*(?<Title>[\s\S]*?)$";
  151. Match match = Regex.Match(outputData, pattern, RegexOptions.IgnoreCase);
  152. if (match.Success)
  153. {
  154. title = match.Groups["Title"].Value;
  155. startTagFound = true;
  156. }
  157. }
  158. count = streamReader.Read(buf, 0, 256);
  159. }
  160. streamReader.Close();
  161. if (!string.IsNullOrEmpty(title))
  162. {
  163. int maxTitle = Convert.ToInt32(GetOptionValue("Max Title"));
  164. if (title.Length > (int)maxTitle)
  165. {
  166. title = string.Format("{0}...", title.Substring(0, (int)maxTitle));
  167. }
  168. Bot.IRC.Command.SendPrivateMessage(message.Channel, string.Format("[URL] {0} ({1})", HttpUtility.HtmlDecode(HttpUtility.UrlDecode(StripTagsCharArray(title))), url.Host));
  169. }
  170. }
  171. /// <summary>
  172. /// Remove HTML tags from string using char array.
  173. /// </summary>
  174. public static string StripTagsCharArray(string source)
  175. {
  176. char[] array = new char[source.Length];
  177. int arrayIndex = 0;
  178. bool inside = false;
  179. for (int i = 0; i < source.Length; i++)
  180. {
  181. char let = source[i];
  182. if (let == '<')
  183. {
  184. inside = true;
  185. continue;
  186. }
  187. if (let == '>')
  188. {
  189. inside = false;
  190. continue;
  191. }
  192. if (!inside)
  193. {
  194. array[arrayIndex] = let;
  195. arrayIndex++;
  196. }
  197. }
  198. return new string(array, 0, arrayIndex);
  199. }
  200. public static string ToFileSize(long source)
  201. {
  202. const int byteConversion = 1024;
  203. double bytes = Convert.ToDouble(source);
  204. if (bytes >= Math.Pow(byteConversion, 3)) //GB Range
  205. {
  206. return string.Concat(Math.Round(bytes / Math.Pow(byteConversion, 3), 2), " GB");
  207. }
  208. else if (bytes >= Math.Pow(byteConversion, 2)) //MB Range
  209. {
  210. return string.Concat(Math.Round(bytes / Math.Pow(byteConversion, 2), 2), " MB");
  211. }
  212. else if (bytes >= byteConversion) //KB Range
  213. {
  214. return string.Concat(Math.Round(bytes / byteConversion, 2), " KB");
  215. }
  216. else //Bytes
  217. {
  218. return string.Concat(bytes, " Bytes");
  219. }
  220. }
  221. private string GetYoutubeDescription(string ID)
  222. {
  223. string description = string.Empty;
  224. string urlTemplate = "https://www.googleapis.com/youtube/v3/videos?part=snippet,statistics,contentDetails&id={0}&key={1}";
  225. Uri searchUrl = new Uri(string.Format(urlTemplate, ID, GetOptionValue("API Key")));
  226. WebClient web = new WebClient();
  227. web.Encoding = Encoding.UTF8;
  228. try
  229. {
  230. string page = web.DownloadString(searchUrl);
  231. JObject parsed = (JObject)JsonConvert.DeserializeObject(page);
  232. var data = parsed["items"].First();
  233. description = string.Format("\u0002{0}\u000F", data["snippet"]["title"]);
  234. if (data["contentDetails"]["duration"] == null)
  235. {
  236. return description;
  237. }
  238. string length = data["contentDetails"]["duration"].Value<string>();
  239. Regex lengthRegex = new Regex(@"PT((?<Days>[0-9]+)D)?((?<Hours>[0-9]+)H)?((?<Minutes>[0-9]+)M)?((?<Seconds>[0-9]+)S)?");
  240. Match lengthMatch = lengthRegex.Match(length);
  241. double totalTime = 0;
  242. if (lengthMatch.Groups["Days"].Success)
  243. totalTime += 86400.0 * Convert.ToDouble(lengthMatch.Groups["Days"].Value);
  244. if (lengthMatch.Groups["Hours"].Success)
  245. totalTime += 3600.0 * Convert.ToDouble(lengthMatch.Groups["Hours"].Value);
  246. if (lengthMatch.Groups["Minutes"].Success)
  247. totalTime += 60.0 * Convert.ToDouble(lengthMatch.Groups["Minutes"].Value);
  248. if (lengthMatch.Groups["Seconds"].Success)
  249. totalTime += Convert.ToDouble(lengthMatch.Groups["Seconds"].Value);
  250. TimeSpan duration = TimeSpan.FromSeconds(totalTime);
  251. description += string.Format(" | Length: \u0002{0}\u000F", duration.ToString("g"));
  252. if (data["statistics"] != null)
  253. {
  254. JToken stats = data["statistics"];
  255. int likes = (stats["likeCount"] != null) ? stats["likeCount"].Value<int>() : 0;
  256. string pluralLikes = (likes > 1) ? "s" : string.Empty;
  257. int dislikes = (stats["dislikeCount"] != null) ? stats["dislikeCount"].Value<int>() : 0;
  258. string pluralDislikes = (dislikes > 1) ? "s" : string.Empty;
  259. double percent = 100.0 * ((double)likes / (likes + dislikes));
  260. description += string.Format(" | Rating: {0} Like{1}, {2} Dislike{3} (\u0002{4}\u000F%)", likes, pluralLikes, dislikes, pluralDislikes, Math.Round(percent, 1));
  261. description += string.Format(" | Views: \u0002{0}\u000F", data["statistics"]["viewCount"].Value<int>());
  262. }
  263. DateTime uploadDate = Convert.ToDateTime(data["snippet"]["publishedAt"].Value<string>());
  264. description += string.Format(" | Uploaded By: \u0002{0}\u000F on \u0002{1}\u000F", data["snippet"]["channelTitle"].Value<string>(), uploadDate.ToString("R"));
  265. if (data["contentDetails"]["contentRating"] != null)
  266. {
  267. description += " | \u0002NSFW\u000F";
  268. }
  269. }
  270. catch (WebException ex)
  271. {
  272. description = string.Empty;
  273. }
  274. return description;
  275. }
  276. }
  277. }