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 14KB

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