{"id":453,"date":"2012-01-20T22:13:50","date_gmt":"2012-01-21T03:13:50","guid":{"rendered":"http:\/\/www.mageuzi.com\/blog\/?p=453"},"modified":"2012-01-21T13:34:22","modified_gmt":"2012-01-21T18:34:22","slug":"my-little-twitter-bot","status":"publish","type":"post","link":"http:\/\/www.mageuzi.com\/blog\/2012\/01\/20\/my-little-twitter-bot\/","title":{"rendered":"My Little Twitter Bot"},"content":{"rendered":"<p>It all started when @ndoto replied to <a href=\"https:\/\/twitter.com\/#!\/mageuzi\/status\/156809285907648512\" target=\"_blank\">one of my \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d tweets<\/a> saying that <a href=\"https:\/\/twitter.com\/#!\/ndoto\/status\/156809665852866560\" target=\"_blank\">he wished there was a Big Macintosh Twitter bot<\/a> that would reply with an \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d if you sent a tweet containing \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d.<\/p>\n<p>For those who aren\u00e2\u20ac\u2122t in the know, Big Macintosh is a character on the cartoon <em>My Little Pony: Friendship is Magic<\/em>. It\u00e2\u20ac\u2122s a slight re-imagining of the original show, headed by the same creative mind behind <em>Foster\u00e2\u20ac\u2122s Home for Imaginary Friends<\/em> \u00e2\u20ac\u201c an awesome show with clever writing. Needless to say, that same maturity (but kid-appeal) carries over to the new My Little Pony. I suppose I should clarify that I\u00e2\u20ac\u2122m not enough of a fan to call myself a brony, but I do think the show is about 20% cooler than most other things on television \u00e2\u20ac\u201c and Big Macintosh is by far my favorite character. :)<\/p>\n<p>I\u00e2\u20ac\u2122ve always wanted to make a Twitter bot, so I jumped at the opportunity. In this post, I\u00e2\u20ac\u2122d like to share some of the technical details, and decision making, that brought @<a href=\"http:\/\/twitter.com\/BigMacinbot\" target=\"_blank\">BigMacinbot<\/a> to life.<\/p>\n<p><!--more--><\/p>\n<p>The first thing I had to decide was how I was going to interface with Twitter. From my experience with <a href=\"http:\/\/mageuzi.com\/trowl\" target=\"_blank\">Trowl<\/a>, I figured I could throw together a simple C# program, running on my home computer, using the Twitter library I had already created. The downside, though, is that if my internet connection went down, or my computer powered off, the bot would go quiet. So instead, I decided to write a PHP script, and host it on my remote server space. I\u00e2\u20ac\u2122d also use cron to automatically run the script every five minutes. Finally, since I was already familiar with the Twitter API, I didn\u00e2\u20ac\u2122t feel the need to write the API calls from scratch. I used a PHP Twitter library, <a href=\"https:\/\/github.com\/themattharris\/tmhOAuth\" target=\"_blank\">tmhOAuth<\/a>, that had everything I needed, and was simple to use.<\/p>\n<p>With that decided, I turned my attention to how the bot, itself, would work. It seemed very simple at first: search Twitter, then send a reply to every tweet containing \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d. As I kept thinking about it, though, I realized just how annoying that would be. If someone used that phrase often enough, they\u00e2\u20ac\u2122d end up being spammed by the bot. The point of this was to have a bit of fun, not annoy people. <\/p>\n<p>To confirm my suspicions, I created a very simple script that just did the \u00e2\u20ac\u0153search Twitter\u00e2\u20ac\u009d part, and emailed the results. I let this run over the course of a couple days and, indeed, more people than I expected used \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d &#8212; and used it frequently. With this in mind, I started to create a set of rules that a tweet would have to pass through before the bot would send a reply:<\/p>\n<p><strong><font size=\"3\">Big Macintosh\u00e2\u20ac\u2122s Rules of Agreement        <br \/><\/font><\/strong><\/p>\n<ol>\n<li>Tweet was sent within the last two hours. <\/li>\n<li>Not a retweet <\/li>\n<li>Tweet says \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d somewhere. (Twitter name cannot contain \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d.) <\/li>\n<li>User isn\u00e2\u20ac\u2122t being ignored. If a user really doesn\u00e2\u20ac\u2122t like Big Macinbot, they can reply with \u00e2\u20ac\u0153nope\u00e2\u20ac\u009d, and they\u00e2\u20ac\u2122ll never receive another reply. <\/li>\n<li>The user has never received a reply from Big Macinbot, or they haven\u00e2\u20ac\u2122t received a reply recently. The definition of \u00e2\u20ac\u0153recently\u00e2\u20ac\u009d is based on probability. If the last time the user received a reply was within two weeks, Big Macinbot looks to see how long ago it was. The closer to two weeks, the more likely a reply will be sent. After two weeks, a reply is definitely sent. Here is the code, for those interested: <\/li>\n<\/ol>\n<div style=\"border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100.42%; padding-right: 4px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; height: 177px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px\" id=\"codeSnippetWrapper\">\n<div style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\" id=\"codeSnippet\">\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum1\">   1:<\/span> $diff = time() \u00e2\u20ac\u201c $previous_reply_timestamp;<\/pre>\n<p><!--CRLF--><\/p>\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum2\">   2:<\/span> $prob = ($diff \/ 1209600) * 100; <span style=\"color: #008000\">\/\/ Number of seconds in two weeks.<\/span><\/pre>\n<p><!--CRLF--><\/p>\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum3\">   3:<\/span>&#160; <\/pre>\n<p><!--CRLF--><\/p>\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum4\">   4:<\/span> $rand = rand(1,100);<\/pre>\n<p><!--CRLF--><\/p>\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum5\">   5:<\/span>&#160; <\/pre>\n<p><!--CRLF--><\/p>\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum6\">   6:<\/span> <span style=\"color: #0000ff\">if<\/span> ($rand &gt; 1 &amp;&amp; $rand &lt; $prob)<\/pre>\n<p><!--CRLF--><\/p>\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum7\">   7:<\/span> {<\/pre>\n<p><!--CRLF--><\/p>\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum8\">   8:<\/span>     <span style=\"color: #0000ff\">return<\/span> <span style=\"color: #0000ff\">true<\/span>;<\/pre>\n<p><!--CRLF--><\/p>\n<pre style=\"border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px\"><span style=\"color: #606060\" id=\"lnum9\">   9:<\/span> }<\/pre>\n<p><!--CRLF--><\/div>\n<\/div>\n<p>Coding these rules wasn\u00e2\u20ac\u2122t too difficult \u00e2\u20ac\u201c the trickiest part was building a simple database to keep track of users, and when their last reply was sent. Relying on a database makes the script a bit more complex, but the ability to stagger Big Macinbot\u00e2\u20ac\u2122s replies makes it worthwhile.<\/p>\n<p>After implementing this base functionality, I wondered what should happen if someone replied to Big Macinbot. Most other bots, as far as I knew, didn\u00e2\u20ac\u2122t do anything if you replied or mentioned them. But I didn\u00e2\u20ac\u2122t want to miss out on a chance to give this bot a little more personality \u00e2\u20ac\u201c it would still respond with \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d, but the interaction could be fun. Since I was already checking mentions for ignore requests, I just added another case that sent a reply back if it was a normal mention. To build upon the goal of adding some more personality, I actually have Big Macinbot choose from three random responses: Eeyup. \/ Eeyup! \/ \u00e2\u20ac\u00a6 Eeeyup?<\/p>\n<p>Another reason for the random responses is to try and get around Twitter\u00e2\u20ac\u2122s \u00e2\u20ac\u0153duplicate status\u00e2\u20ac\u009d error \u00e2\u20ac\u201c Twitter denies a status posting if it\u00e2\u20ac\u2122s the same as your previous status. Unfortunately, it seems as though Twitter doesn\u00e2\u20ac\u2122t just check your last status, like I thought, but all of your recent statuses. So right now, once someone exhausts the three random responses, Big Macinbot goes quiet due to Twitter errors.<\/p>\n<p>At the beginning, though, I wasn\u00e2\u20ac\u2122t even sure if anyone would bother replying. Everything else was in place, and seemed to be working, so it was time to move forward. On Saturday, January 14, 2012, Big Macinbot came to life.<\/p>\n<p><strong>The Reaction<\/strong><\/p>\n<p><font color=\"#000000\">I have to admit that about halfway through coding the bot \u00e2\u20ac\u201c about the time that I was perfecting the Rules of Agreement \u00e2\u20ac\u201c I wondered if I should keep going. I started to think that no one was going to like the bot; that everyone would block and it would be done within a week or two.<\/font><\/p>\n<p><font color=\"#000000\">Well, all I can say is that Twitter bronies are awesome! Not only does everyone seem to love Big Macinbot, but they reply to and follow the bot on a regular basis. It has been fun seeing the reactions, and the general love for Big Macintosh. I\u00e2\u20ac\u2122ve had the pleasure of discovering a few very nice folks, too, so that has been a wonderful bonus. :)<\/font><\/p>\n<p><font color=\"#000000\">Because of Big Macinbot\u00e2\u20ac\u2122s popularity, I\u00e2\u20ac\u2122ve been making regular tweaks and updates to how he works, and I\u00e2\u20ac\u2122m currently working on a suggestion to have Big Macinbot reply to everyone when being mentioned. I never expected him to gain such a following, but I\u00e2\u20ac\u2122m really happy he did, because I think he\u00e2\u20ac\u2122s a really fun bot! I just hope Twitter doesn\u00e2\u20ac\u2122t suspend the account \u00e2\u20ac\u201c I\u00e2\u20ac\u2122ve tried to be light on Twitter\u00e2\u20ac\u2122s resources, and follow best practices, so hopefully they\u00e2\u20ac\u2122ll let him keep going. Eeyup!<\/font><\/p>\n<p><font color=\"#000000\">I\u00e2\u20ac\u2122d like to finish this post with some of my favorite reactions and replies to Big Macinbot. Thank you again to everypony for such a wonderful welcome to Twitter! If anyone has suggestions, or questions about what I wrote about here, please feel free to post a comment, or send me a message at @<a href=\"http:\/\/twitter.com\/mageuzi\" target=\"_blank\">mageuzi<\/a>! :)<\/font><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\" data-in-reply-to=\"158244122107461632\">\n<p>@<a href=\"https:\/\/twitter.com\/AH_Dylon\">AH_Dylon<\/a> Dude, I just had an encounter with the best Twitterbot ever.@<a href=\"https:\/\/twitter.com\/BigMacinbot\">BigMacinbot<\/a>. So legit.<\/p>\n<p>\u00e2\u20ac\u201d Chris P. Come here! (@tictac472_FTW) <a href=\"https:\/\/twitter.com\/tictac472_FTW\/status\/158249755200331776\" data-datetime=\"2012-01-14T18:10:56+00:00\">January 14, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\" data-in-reply-to=\"158357592991731712\">\n<p>@<a href=\"https:\/\/twitter.com\/BigMacinbot\">BigMacinbot<\/a> I LOVE YOU.<\/p>\n<p>\u00e2\u20ac\u201d Justin Bieber fan.\u00e0\u00b2\u0152(@HackedByBieber) <a href=\"https:\/\/twitter.com\/HackedByBieber\/status\/158357834101301248\" data-datetime=\"2012-01-15T01:20:24+00:00\">January 15, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\" data-in-reply-to=\"158601704345042944\">\n<p>@<a href=\"https:\/\/twitter.com\/BigMacinbot\">BigMacinbot<\/a> :3 that made my day<\/p>\n<p>\u00e2\u20ac\u201d DMName (@SirDMName) <a href=\"https:\/\/twitter.com\/SirDMName\/status\/158601756148899841\" data-datetime=\"2012-01-15T17:29:40+00:00\">January 15, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\">\n<p>Eeyup.RT @<a href=\"https:\/\/twitter.com\/foalpapers\">foalpapers<\/a>: Eeyup. RT @<a href=\"https:\/\/twitter.com\/IndieLexy\">IndieLexy<\/a>: Eeyup RT @<a href=\"https:\/\/twitter.com\/HybridMisfit\">HybridMisfit<\/a>: Eeyupception? RT @<a href=\"https:\/\/twitter.com\/Tempy_\">Tempy_<\/a>: RT @<a href=\"https:\/\/twitter.com\/foalpapers\">foalpapers<\/a>: Eeyup. RT @<a href=\"https:\/\/twitter.com\/BigMacinbot\">BigMacinbot<\/a>: Eeyup.<\/p>\n<p>\u00e2\u20ac\u201d Lexy (@IndieLexy) <a href=\"https:\/\/twitter.com\/IndieLexy\/status\/160396551515144192\" data-datetime=\"2012-01-20T16:21:32+00:00\">January 20, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\" data-in-reply-to=\"159858823987855360\">\n<p>@<a href=\"https:\/\/twitter.com\/BigMacinbot\">BigMacinbot<\/a> I agree<\/p>\n<p>\u00e2\u20ac\u201d Please Stand By (@StandbyPlease) <a href=\"https:\/\/twitter.com\/StandbyPlease\/status\/160005545816887296\" data-datetime=\"2012-01-19T14:27:49+00:00\">January 19, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\" data-in-reply-to=\"159389187706068994\">\n<p>@<a href=\"https:\/\/twitter.com\/that_taco_guy\">that_taco_guy<\/a> &#8230;Eeyup?<\/p>\n<p>\u00e2\u20ac\u201d Big Macintosh (@BigMacinbot) <a href=\"https:\/\/twitter.com\/BigMacinbot\/status\/159389420473171968\" data-datetime=\"2012-01-17T21:39:33+00:00\">January 17, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\" data-in-reply-to=\"159014052650156032\">\n<p>@<a href=\"https:\/\/twitter.com\/norninja\">norninja<\/a> Eeyup!<\/p>\n<p>\u00e2\u20ac\u201d Big Macintosh (@BigMacinbot) <a href=\"https:\/\/twitter.com\/BigMacinbot\/status\/159014436466733056\" data-datetime=\"2012-01-16T20:49:30+00:00\">January 16, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\" data-in-reply-to=\"159279948773867521\">\n<p>@<a href=\"https:\/\/twitter.com\/BigMacinbot\">BigMacinbot<\/a> This conversation seems one-sided.<\/p>\n<p>\u00e2\u20ac\u201d Philip Kardefelt (@Terkup) <a href=\"https:\/\/twitter.com\/Terkup\/status\/159280794341355524\" data-datetime=\"2012-01-17T14:27:55+00:00\">January 17, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n<blockquote class=\"twitter-tweet tw-align-center\" data-in-reply-to=\"158991147346309121\">\n<p>@<a href=\"https:\/\/twitter.com\/Kurraga\">Kurraga<\/a> Eeyup!<\/p>\n<p>\u00e2\u20ac\u201d Big Macintosh (@BigMacinbot) <a href=\"https:\/\/twitter.com\/BigMacinbot\/status\/158991792115679232\" data-datetime=\"2012-01-16T19:19:31+00:00\">January 16, 2012<\/a><\/p><\/blockquote>\n<p><script src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>It all started when @ndoto replied to one of my \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d tweets saying that he wished there was a Big Macintosh Twitter bot that would reply with an \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d if you sent a tweet containing \u00e2\u20ac\u0153eeyup\u00e2\u20ac\u009d. For those who aren\u00e2\u20ac\u2122t in the know, Big Macintosh is a character on the cartoon My Little Pony: Friendship [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[19,33],"tags":[135,133,132,136,134,137,12,61],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/posts\/453"}],"collection":[{"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/comments?post=453"}],"version-history":[{"count":9,"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/posts\/453\/revisions"}],"predecessor-version":[{"id":466,"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/posts\/453\/revisions\/466"}],"wp:attachment":[{"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/media?parent=453"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/categories?post=453"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.mageuzi.com\/blog\/wp-json\/wp\/v2\/tags?post=453"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}