root/trunk/Twitterbot/Twitterbot.cs

Revision 274, 9.7 KB (checked in by tyler, 2 years ago)

Tighten up the code a bit, add a spoofed user agent >_>

Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Net;
5using System.Text;
6using System.Threading;
7using System.Web;
8using System.Web.Script.Serialization;
9using System.Xml;
10using Rss;
11
12public class Twitterbot
13{
14        public const string TwitterUrl = "http://twitter.com/statuses/update.xml";
15        public const string TinyUrl = "http://urlenco.de/PostJSON.aspx?encode=";
16        public const int TwitterMax = 3; // maximum number of feed updates to pull
17        public const int HistoryMax     = 10; // maximum number of backlogged feed items to store
18
19        public static void Main(string[] args)
20        {
21                bool slowAtNight = false;
22               
23                if ( (args.Length < 3) || (args.Length > 4) )
24                {
25                        Console.WriteLine("Twitterbot.exe <feed file> <minutes to sleep> <night time slowdown>");
26                        Console.WriteLine("Usage:");
27                        Console.WriteLine("mono Twitterbot.exe feeds.xml 30 yes");
28                       
29                        Console.WriteLine("");
30                        Console.WriteLine("Enabling night time slowdown will cause the Twitterbot to double its");
31                        Console.WriteLine("sleep interval between the hours of 12:00 a.m. and 6 a.m."); 
32                        return;
33                }
34       
35                string feedFile = args[0];
36                int sleep = Convert.ToInt32(args[1]);
37               
38                if ( (args[2] == "yes") || (args[2] == "y") )
39                        slowAtNight = true;
40               
41                List<Feed> feedList = new List<Feed>();
42                       
43                Console.WriteLine("Reading {0} and looping {1} minutes", feedFile, sleep);
44               
45                /*
46                 *      The following block is quite basic, open the feed xml file and
47                 *      generate a List of Feed objects.
48                 */
49                ////////////////////////////////////////////////////////////////////////
50                XmlDocument feedXml = new XmlDocument();
51                XmlNodeList feeds;
52                FileStream stream;
53               
54                if (File.Exists(feedFile))
55                {
56                        stream = File.OpenRead(feedFile);
57                }
58                else
59                {
60                        Console.WriteLine("File {0} not found", feedFile);
61                        return;
62                }
63
64                feedXml.Load(stream);
65                feeds = feedXml.GetElementsByTagName("feed");
66               
67                foreach (XmlNode feed in feeds)
68                {
69                        string name = feed.Attributes["name"].InnerText;
70                        string url = feed.Attributes["url"].InnerText;
71                        string twitter = feed.Attributes["twitter"].InnerText;
72                        string pass = feed.Attributes["password"].InnerText;
73                       
74                        feedList.Add(new Feed(name, url, twitter, pass));
75                }
76               
77                stream.Close();
78                ////////////////////////////////////////////////////////////////////////
79                ////////////////////////////////////////////////////////////////////////
80
81
82                /*
83                 *      Our core runloop will iterate every 'sleep' minutes, first udpating
84                 *      each one of our feeds, checking for duplicates, posting new entries
85                 *      to the Feed's twitter account, and finally backlogging entries
86                 */
87                ////////////////////////////////////////////////////////////////////////
88                do
89                {
90                        foreach (Feed feed in feedList)
91                        {
92                                Console.WriteLine("Reading {0}", feed.Name);
93                                try
94                                {
95                                        HttpWebRequest rssRequest = GenerateGetOrPostRequest(feed.Url, "GET", null, null, null); 
96                                        feed.Rss = RssFeed.Read(rssRequest);
97                                }
98                                catch (Exception ex)
99                                {
100                                        Console.WriteLine("RSS.NET received an exception!{0}{1}", 
101                                                Environment.NewLine, ex);
102                                        continue;
103                                }
104
105                                List<RssItem> tempList = new List<RssItem>();
106
107                                foreach (RssChannel channel in feed.Rss.Channels)
108                                {
109                                        int count = 0;
110                                       
111                                        foreach (RssItem item in channel.Items)
112                                        {                       
113                                                if (count == TwitterMax)
114                                                        break;
115                                                if (feed.LastItems.Count > 0)
116                                                {
117                                                        bool found = false;
118                                                        foreach (RssItem lastItem in feed.LastItems)
119                                                        {
120                                                                if (item.Title == lastItem.Title)
121                                                                {
122                                                                        found = true;
123                                                                        break;
124                                                                }
125                                                        }
126                                                       
127                                                        if (!found)
128                                                                tempList.Add(item);
129                                                }
130                                                else
131                                                {
132                                                        tempList.Add(item);
133                                                }
134                                                ++count;
135                                        }
136                                        break; // on the off-chance there is more than one channel
137                                }
138
139                                foreach (RssItem item in tempList)
140                                {
141                                        // Prepare to post to twitter
142                                        string post = PrepareTwitterStatus(item);
143                                        Console.WriteLine("[{0}] Preparing post: {1}", DateTime.Now, post);
144                                       
145                                        if (!PostToTwitter(feed, post))
146                                                Console.WriteLine("[{0}] Failed to post to twitter!", DateTime.Now);
147
148                                        // Patiently count to five to reduce spammage
149                                        Thread.Sleep(5000);
150                                }
151                                // Add our added items to the backlog list
152                                feed.AddItems(tempList);
153                        }
154                        Console.WriteLine("--------");
155               
156                        // If we're slowing down at night, check to see if we're between 12:00 and 6:00 exclusive
157                        if ( (slowAtNight) && (DateTime.Now.Hour >= 0) && (DateTime.Now.Hour < 6) )
158                        {
159                                int slowSleep = (sleep * 2);
160                                Console.WriteLine("Doubling interval of {0} minute(s) to {1} minute(s) for night time hours", sleep, slowSleep);
161                                Thread.Sleep((slowSleep * 1000)*60);
162                        }
163                        else                   
164                        {
165                                Thread.Sleep((sleep * 1000)*60);
166                        }
167                } while (true);
168                ////////////////////////////////////////////////////////////////////////
169                ////////////////////////////////////////////////////////////////////////
170        }
171       
172       
173        public static bool PostToTwitter(Feed feed, string post)
174        {
175                HttpWebRequest request = null;
176                string returnString = string.Empty;                     
177                HttpWebResponse response = null;
178
179                try
180                {
181                        request = GenerateGetOrPostRequest(TwitterUrl, "POST", string.Format("status={0}", post), 
182                                                                                        feed.TwitterName, feed.TwitterPass);
183                        response = (HttpWebResponse)request.GetResponse();
184                        Stream responseStream = response.GetResponseStream( );
185                        StreamReader reader = new StreamReader(responseStream,Encoding.UTF8);
186
187                        try
188                        {
189                                returnString = reader.ReadToEnd( );
190                        }
191                        catch (Exception ex)
192                        {
193                                Console.WriteLine("Received exception! {0}{1}", Environment.NewLine, ex);
194                                return false;
195                        }
196                        finally
197                        {
198                                if (reader != null)
199                                        reader.Close();
200                        }
201                }
202                catch (Exception ex)
203                {
204                        Console.WriteLine("Received exception! {0}{1}", Environment.NewLine, ex);
205                        return false;
206                }
207                finally
208                {
209                        if (response != null)
210                                response.Close();
211                }               
212
213                return true;
214        }
215
216
217        public static string PrepareTwitterStatus(RssItem item)
218        {
219                string postString;
220                string titleString = string.Empty;
221                bool tainted = false;
222               
223                // This wee little bit of information should ensure we don't add any &#39; shit into the string
224                foreach (char oneChar in item.Title.ToCharArray())
225                {
226                        if ( (oneChar == ';') && (tainted) )
227                        {
228                                tainted = false;
229                                continue;
230                        }
231                        else if (oneChar == '&')
232                        {
233                                tainted = true;
234                                continue;
235                        }
236                        else if (oneChar == ';') 
237                        {
238                                continue;
239                        }
240                        else
241                        {
242                                if (!tainted)
243                                        titleString += oneChar;
244                        }
245                }
246               
247                if (item.Title.Length > 124)
248                {
249                        postString = titleString.Substring(0,124);
250                        postString += ".. ";
251                }
252                else
253                {
254                        postString = titleString;
255                }
256
257                Console.WriteLine(item.Link);
258                postString += string.Format(": {0}", FetchTinyUrl(item.Link));
259               
260                return postString;
261        }
262
263
264        public static string FetchTinyUrl(Uri longUrl)
265        {
266                string tinyurl;
267                string target_url = HttpUtility.UrlEncode(longUrl.ToString());
268
269                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format("{0}{1}", TinyUrl, target_url));
270                HttpWebResponse response = null;
271               
272                try
273                {
274                        response = (HttpWebResponse)request.GetResponse();
275            Stream responseStream = response.GetResponseStream( );
276            StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
277
278            try
279            {
280                tinyurl = reader.ReadToEnd();
281            }
282            catch (Exception ex)
283            {
284                                Console.WriteLine("Received exception! {0}{1}", Environment.NewLine, ex);
285                                return string.Empty;
286            }
287            finally
288            {
289                if (reader != null)
290                        reader.Close();
291            }
292            }
293                catch (Exception ex)
294                {
295                        Console.WriteLine("Received exception! {0}{1}", Environment.NewLine, ex);
296                        return string.Empty;
297                }
298           finally
299           {
300                        if (response != null)
301                       response.Close();
302           }
303               
304                JavaScriptSerializer serializer = new JavaScriptSerializer();
305                Dictionary<string, string> results = serializer.Deserialize<Dictionary<string, string>>(tinyurl);
306                return results["encoded"];
307        }
308       
309
310        public static HttpWebRequest GenerateGetOrPostRequest(string uriString, string method, string postData, string user, string pass)
311    {
312                if ((method.ToUpper() != "GET") && (method.ToUpper() != "POST"))
313                        throw new ArgumentException(method + " is not a valid method.  Use GET or POST.","method");
314       
315                HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(uriString);
316                httpRequest.Method = method;
317                httpRequest.UserAgent = "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.13)";
318
319                if (method.ToUpper() =="POST")
320                {
321                        if ( (user != null) && (pass != null) )
322                        {
323                                httpRequest.Credentials = new NetworkCredential(user, pass);
324                        }
325
326                        // Get the bytes for the request, should be pre-escaped
327                        byte[] bytes = Encoding.UTF8.GetBytes(postData);
328
329                        // Set the content type of the data being posted.
330                        httpRequest.ContentType = "application/x-www-form-urlencoded";
331
332                        // Set the content length of the string being posted.
333                        httpRequest.ContentLength = bytes.Length;
334
335                        Stream requestStream = httpRequest.GetRequestStream();
336                        requestStream.Write(bytes,0,bytes.Length);
337                        // Done updating for POST so close the stream
338                        requestStream.Close();
339                }
340           
341                return httpRequest;
342    }
343
344}
345
346               
347public class Feed
348{
349        public string Name;
350        public string Url;
351        public string TwitterName;
352        public string TwitterPass;
353        public RssFeed Rss;
354        public List<RssItem> LastItems;
355
356        public Feed(string name, string url, string twitter, string pass)
357        {
358                Name = name;
359                Url = url;
360                TwitterName = twitter;
361                TwitterPass = pass;
362                LastItems = new List<RssItem>(10);
363        }
364       
365        public void AddItems(List<RssItem> items)
366        {
367                // If we've exceeded our max, remove items.Count from the front of the list
368                // and add items to the end of the list
369                if (LastItems.Count > Twitterbot.HistoryMax)
370                {
371                        for (int i = 0; i < items.Count; ++i)
372                        {
373                                LastItems.RemoveAt(i);
374                        }
375                }       
376                       
377                LastItems.AddRange(items);
378        }
379}
Note: See TracBrowser for help on using the browser.