commit 25a3b3a89b54d7782bed1ac30c01e8aed4329af0 Author: tyler Date: Wed Jan 24 06:01:53 2007 +0000 Initial import of the Twitterbot git-svn-id: https://source.geekisp.com/bleep/trunk/Twitterbot@37 a256dd88-e320-0410-9161-d397f098afaa diff --git a/RSS.NET.dll b/RSS.NET.dll new file mode 100755 index 0000000..8ad5074 Binary files /dev/null and b/RSS.NET.dll differ diff --git a/Twitterbot.cs b/Twitterbot.cs new file mode 100644 index 0000000..3cb3df0 --- /dev/null +++ b/Twitterbot.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Xml; +using Rss; + +public class Twitterbot +{ + public const string TwitterUrl = "http://twitter.com/statuses/update.xml"; + public const string TinyUrl = "http://tinyurl.com/api-create.php?url="; + public const int TwitterMax = 2; // maximum number of feed updates to pull + + public static void Main(string[] args) + { + + if ( (args.Length < 3) || (args.Length > 4) ) + { + Console.WriteLine("Twitterbot.exe FEEDFILE [--loop ]"); + return; + } + + string feedFile = args[0]; + int sleep = Convert.ToInt32(args[2]); + List feedList = new List(); + + Console.WriteLine("Reading {0} and looping {1} minutes", feedFile, sleep); + XmlDocument feedXml = new XmlDocument(); + XmlNodeList feeds; + FileStream stream; + + if (File.Exists(feedFile)) + { + stream = File.OpenRead(feedFile); + } + else + { + throw new Exception(String.Format("File {0} not found", feedFile)); + } + + feedXml.Load(stream); + feeds = feedXml.GetElementsByTagName("feed"); + + foreach (XmlNode feed in feeds) + { + string name = feed.Attributes["name"].InnerText; + string url = feed.Attributes["url"].InnerText; + string twitter = feed.Attributes["twitter"].InnerText; + string pass = feed.Attributes["password"].InnerText; + + feedList.Add(new Feed(name, url, twitter, pass)); + } + + do + { + foreach (Feed feed in feedList) + { + Console.WriteLine("Reading {0}", feed.Name); + feed.Rss = RssFeed.Read(feed.Url); + + foreach (RssChannel channel in feed.Rss.Channels) + { + List tempList = new List(); + int count = 0; + + foreach (RssItem item in channel.Items) + { + if (count == TwitterMax) + break; + + if (feed.LastItems.Count > 0) + { + bool found = false; + foreach (RssItem lastItem in feed.LastItems) + { + if (item.Title == lastItem.Title) + found = true; + } + + if (!found) + tempList.Add(item); + + } + else + { + tempList.Add(item); + } + + ++count; + } + + feed.LastItems.Clear(); + feed.LastItems.AddRange(tempList); + break; // on the off-chance there is more than one channel + } + + foreach (RssItem item in feed.LastItems) + { + // Prepare to post to twitter + string post = PrepareTwitterStatus(item); + Console.WriteLine("Preparing post: {0}", post); + + if (!PostToTwitter(feed, post)) + { + Console.WriteLine("Failed to post to twitter!"); + } + + // Patiently count to five to reduce spammage + Thread.Sleep(5000); + } + } + + Console.WriteLine("--------"); + + Thread.Sleep((sleep * 1000)*60); + } while (true); + } + + public static bool PostToTwitter(Feed feed, string post) + { + HttpWebRequest request = GenerateGetOrPostRequest(TwitterUrl, "POST", string.Format("status={0}", post), + feed.TwitterName, feed.TwitterPass); + string returnString = string.Empty; + HttpWebResponse response = null; + + try + { + response = (HttpWebResponse)request.GetResponse(); + Stream responseStream = response.GetResponseStream( ); + StreamReader reader = new StreamReader(responseStream,Encoding.UTF8); + + try + { + returnString = reader.ReadToEnd( ); + } + catch (Exception ex) + { + Console.WriteLine("Received exception! {0}{1}", Environment.NewLine, ex); + return false; + } + finally + { + if (reader != null) + reader.Close(); + } + } + catch (Exception ex) + { + Console.WriteLine("Received exception! {0}{1}", Environment.NewLine, ex); + return false; + } + finally + { + if (response != null) + response.Close(); + } + + return true; + } + + public static string PrepareTwitterStatus(RssItem item) + { + string postString; + string titleString = string.Empty; + bool tainted = false; + + // This wee little bit of information should ensure we don't add any ' shit into the string + foreach (char oneChar in item.Title.ToCharArray()) + { + if ( (oneChar == ';') && (tainted) ) + { + tainted = false; + continue; + } + else if (oneChar == '&') + { + tainted = true; + continue; + } + else if (oneChar == ';') + { + continue; + } + else + { + if (!tainted) + titleString += oneChar; + } + } + + if (item.Title.Length > 124) + { + postString = titleString.Substring(0,124); + postString += ".. "; + } + else + { + postString = titleString; + } + + postString += string.Format(": {0}", FetchTinyUrl(item.Link)); + + return postString; + } + + public static string FetchTinyUrl(Uri longUrl) + { + string tinyurl; + + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format("{0}{1}", TinyUrl, longUrl.ToString())); + HttpWebResponse response = null; + + try + { + response = (HttpWebResponse)request.GetResponse(); + Stream responseStream = response.GetResponseStream( ); + StreamReader reader = new StreamReader(responseStream, Encoding.UTF8); + + try + { + tinyurl = reader.ReadToEnd(); + } + catch (Exception ex) + { + Console.WriteLine("Received exception! {0}{1}", Environment.NewLine, ex); + return string.Empty; + } + finally + { + if (reader != null) + reader.Close(); + } + } + catch (Exception ex) + { + Console.WriteLine("Received exception! {0}{1}", Environment.NewLine, ex); + return string.Empty; + } + finally + { + if (response != null) + response.Close(); + } + + return tinyurl; + } + + public static HttpWebRequest GenerateGetOrPostRequest(string uriString, string method, string postData, string user, string pass) + { + if ((method.ToUpper() != "GET") && (method.ToUpper() != "POST")) + throw new ArgumentException(method + " is not a valid method. Use GET or POST.","method"); + + HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(uriString); + httpRequest.Method = method; + + if (method.ToUpper() =="POST") + { + if ( (user != null) && (pass != null) ) + { + httpRequest.Credentials = new NetworkCredential(user, pass); + } + + // Get the bytes for the request, should be pre-escaped + byte[] bytes = Encoding.UTF8.GetBytes(postData); + + // Set the content type of the data being posted. + httpRequest.ContentType = "application/x-www-form-urlencoded"; + + // Set the content length of the string being posted. + httpRequest.ContentLength = bytes.Length; + + Stream requestStream = httpRequest.GetRequestStream(); + requestStream.Write(bytes,0,bytes.Length); + // Done updating for POST so close the stream + requestStream.Close(); + } + + return httpRequest; + } + +} + +public class Feed +{ + public string Name; + public string Url; + public string TwitterName; + public string TwitterPass; + public RssFeed Rss; + public List LastItems; + + public Feed(string name, string url, string twitter, string pass) + { + Name = name; + Url = url; + TwitterName = twitter; + TwitterPass = pass; + LastItems = new List(10); + } +} diff --git a/Twitterbot.exe b/Twitterbot.exe new file mode 100755 index 0000000..443f64b Binary files /dev/null and b/Twitterbot.exe differ diff --git a/bot.build b/bot.build new file mode 100644 index 0000000..064f976 --- /dev/null +++ b/bot.build @@ -0,0 +1,27 @@ + + + + + NAnt build file for the C# Twitterbot + + + + + + + + + + + + + + + + + + + + + + diff --git a/feeds.sample.xml b/feeds.sample.xml new file mode 100644 index 0000000..05d6c46 --- /dev/null +++ b/feeds.sample.xml @@ -0,0 +1,5 @@ + + + + +