Flash AS3 Search Twitter API

At some point in your Flash career you will be asked to implement some sort of Flash widget that communicates with the latest social community apps, like Facebook and Twitter. This post was influenced by a clients request for an application that would display Twitter feeds based on a particular search term . The following example is a proof of concept based off the clients inquiry.

Press the Search button to display the tweet results. You can use a variety of search operators in your query. For a list of available operators check out http://search.twitter.com/operators


NOTE** Due to Twitter limitations on the amount of queries a user can make in an hour, this may not be the best solution for high traffic websites. There are alternative approaches, which maybe the subject of an upcoming post.

Thanks to the open source Flash community and the Twitter API, there are a few existing Twitter Flash API libraries we can choose from. The following is a list of current libraries you can find on the world wide web:

  • TwitterScript by Michael Galpin. AS3 API, originally from Twitter, now open sourced.
  • SWX Twitter API by Aral Balkan.
  • Tweetr by Sandro Duccesschi. AS3, supports the REST API, Search API, and URL shortening.
  • Coderanger by Dan Petitt. Flex/Air OAuth library class.
  • What can these Twitter Libraries do? For the most part they can:

  • authenticate a user
  • set authenticated user’s status
  • set authenticated user’s mobile notifications on/off
  • return a list of friends and their statuses
  • return a public user or a friend of an authenticated user’s timeline
  • return authenticated user’s friends’ timeline
  • return public timeline
  • add list members
  • add list subscriptions
  • block users
  • return list members
  • For the example app, I decided to use theTweetr library. I choose the library based on the Flash Ide that I was developing on at the time, Flash CS3. I also wanted to dig into the libraries source code just in case I wanted to extend or revise it. The other resources used a Flash SWC or SWX. The flash example is pretty straight forward. I utilize the Flash UI components (Button, InputText) for the basic ui and I created a movieclip that is used to display the Twitter feed results.

    The following is the document class:

    /****************************
    * Manuel Gonzalez           *
    * design@stheory.com        *
    * www.stheory.com           *
    * www.codingcolor.com       *
    *****************************/

    package {
      import com.swfjunkie.tweetr.Tweetr;
      import com.swfjunkie.tweetr.events.TweetEvent;
      import com.swfjunkie.tweetr.data.DataParser;
      import com.utils.StringUtils;
      import flash.display.Sprite;
      import flash.events.Event;
      import flash.text.TextField;
      import flash.events.MouseEvent;
      import fl.controls.TextInput;
      import flash.display.MovieClip;

      public class Main extends Sprite {
       
        private var _twtr:Tweetr;
        private var _currentSearchKeyword:String="#earthday";
        private var _lang:String="en";
        private var _numTweets:Number = 10;
        private var _searchArray:Array;
        private var _content:Sprite;
        private var _panelsCreated:Boolean = false;
        private var _tnArray:Array;
        private var _searchButton:Button;
        private var _searchInput:TextInput;
        private var _circleAnimation:CircleAnimation;
       
        public function Main() {
         
          _content = new Sprite();
          _content.x = 20;
          _content.y = 65;
          addChild(_content);
          _searchButton = sButton;
          _searchInput = sInput;
          _searchInput.text = _currentSearchKeyword;
          _twtr = new Tweetr();
          addSearchFormListeners();
         
         
        }
        /*
        Method:addSearchFormListeners
        Parameters:
        Returns:
        */

        private function addSearchFormListeners():void {
          _searchButton.addEventListener(MouseEvent.CLICK, startTwitterSearch);
          _searchButton.enabled = true;
          _searchInput.addEventListener(Event.CHANGE,updateSearchKeywords);
          _searchInput.enabled = true;
        }
        /*
        Method:removeSearchFormListeners
        Parameters:
        Returns:
        */

        private function removeSearchFormListeners():void {
          _searchButton.removeEventListener(MouseEvent.CLICK, startTwitterSearch);
          _searchButton.enabled = false;
          _searchInput.removeEventListener(Event.CHANGE,updateSearchKeywords);
          _searchInput.enabled = false;
        }
        /*
        Method:addTweetrListeners
        Parameters:
        Returns:
        */

        private function addTweetrListeners():void
        {
          _twtr.addEventListener(TweetEvent.COMPLETE,onCompleteHandler);
          _twtr.addEventListener(TweetEvent.FAILED,onFailedHandler);
          _twtr.addEventListener(TweetEvent.STATUS,onStatusHandler);
         
        }
        /*
        Method:removeTweetrListeners
        Parameters:
        Returns:
        */

        private function removeTweetrListeners():void
        {
          _twtr.removeEventListener(TweetEvent.COMPLETE,onCompleteHandler);
          _twtr.removeEventListener(TweetEvent.FAILED,onFailedHandler);
          _twtr.removeEventListener(TweetEvent.STATUS,onStatusHandler);
         
        }
        /*
        Method:startTwitterSearch
        Parameters:
        event:MouseEvent
        Returns:
        */

        private function startTwitterSearch(event:MouseEvent):void {
          searchTwitter();
        }
        /*
        Method:searchTwitter
        Parameters:
        Returns:
        */

        private function searchTwitter():void
        {
          removeSearchFormListeners();
          addTweetrListeners();
          addLoadingAnimation();
          _twtr.search(_currentSearchKeyword,_lang,_numTweets);
        }
        /*
        Method: addLoadingAnimation
        Parameters:
        Returns:
        */

        private function addLoadingAnimation():void {
          _content.visible=false;
          _circleAnimation = new CircleAnimation();
          _circleAnimation.x = (resultBkg.x + resultBkg.width/2) - _circleAnimation.width/2;
          _circleAnimation.y = (resultBkg.y + resultBkg.height/2) - _circleAnimation.height/2;
          addChild(_circleAnimation);
        }
        /*
        Method: removeLoadingAnimation
        Parameters:
        Returns:
        */

        private function removeLoadingAnimation():void {
          removeChild(_circleAnimation);
          _content.visible=true;
        }
        /*
        Method: updateSearchKeywords
        Parameters:
        event:Event
        Returns:
        */

        private function updateSearchKeywords(event:Event):void {
          if (_searchInput.text !="") {
            _currentSearchKeyword = _searchInput.text;
          }
        }
        /*
        Method: onCompleteHandler
        Parameters:
        event:TweetEvent
        Returns:
        */

        private function onCompleteHandler(event:TweetEvent):void
        {
          //trace("Complete " + event.data);
          var sXml:XML = new XML(event.data);
          _searchArray = DataParser.parseSearchResults(sXml);
          createTweetPanel(_searchArray);
          removeTweetrListeners();
          addSearchFormListeners();
          removeLoadingAnimation();
        }
        /*
        Method: onFailedHandler
        Parameters:
        event:TweetEvent
        Returns:
        */

        private function onFailedHandler(event:TweetEvent):void
        {
          //trace("Failed " + event);
        }
        /*
        Method: onStatusHandler
        Parameters:
        event:TweetEvent
        Returns:
        */

        private function onStatusHandler(event:TweetEvent):void
        {
          //trace("Status " + event.data);
        }
        /*
        Method: makeClickable
        Parameters:
        inStr:String
        Returns: String
        */

        private function makeClickable(inStr:String):String
        {
          var str:String = inStr;
          var hasLink:Boolean = false;
          var nstr:Array = str.split(' ');
          var len:int = nstr.length;
         
          for( var i:int = 0; i < len; i++ )
          {
           
            var n = (nstr[i]).indexOf("http://");
            if( n > -1 ){
               nstr[i] ="<font color=\"#0000dd\"><A HREF='"+ nstr[i]+ "' target='_blank'><U>"+ nstr[i]+"</U></A></font>";
              hasLink = true;
            }
          }
          if(hasLink){
            return nstr.join(' ');
          }else{
            return str;
          }
        }
        /*
        Method:createTweetPanel
        Parameters:
        inArray:Array
        Returns:
        */

        private function createTweetPanel(inArray:Array):void {
          if(_panelsCreated)
          {
            var child:int = _content.numChildren;
            while( child -- )
            {
              _content.removeChildAt(child);
            }
          }
         
          _tnArray = new Array();
          var len:int = inArray.length;
          for (var i:uint = 0; i < len; i++) {
            var tn:TweetPanel = new TweetPanel();
            tn.uField.text = StringUtils.beforeFirst(inArray[i].user,"(");
            tn.tField.htmlText =  makeClickable(inArray[i].text);
            //the data objects
            //trace(inArray[i].createdAt);
            //trace(inArray[i].id);
            //trace(inArray[i].link);
            //trace(inArray[i].text);
            //trace(inArray[i].user);
            //trace(inArray[i].userLink);
            //trace(inArray[i].userProfileImage);
            _content.addChild(tn);
            _tnArray.push(tn);
          }
          _panelsCreated = true;
          adjustLayout();
        }
        /*
        Method:adjustLayout
        Parameters:
        Returns:
        */

        private function adjustLayout():void {
          var tnHeight:Number;
          var tnLen:int = _tnArray.length
          for (var j:uint = 0; j < tnLen; j++) {
            _tnArray[j].y = (_tnArray[j].y+ _tnArray[j].height)*j;
            tnHeight = _tnArray[j].height;
          }
         
        }
     
     
     
     
      }
     
    }

    You will notice a few other things in the code that may be of some use to you, like the makeClickable() method. The method essentially takes a string splits it up into an array, looks for “http://” and rebuilds the string with an active link.
    Take the code and improve on it.
    Review the createTweetPanel() method to find trace statements that will assist you on including a userLink or userProfileImage, amongst other things.

    I would like to Thank Sandro Duccesschi for making his library available to the public.

    Enjoy!

    Download Source:
    Flash Twitter Search (559)

    7 thoughts on “Flash AS3 Search Twitter API

    • Pingback: Flash AS3 Search Twitter API- Coding Color » O Empreendedor Neófito

    • March 21, 2010 at 4:52 am
      Permalink

      Hi, Great post about Twitter. I think Twitter is going to be one of the best networks because of the fact that it is supported by so many industries. I also think when Twitter shows some of it’s new functions, returning traffic will increase to show the real growth of the network. Keep up the great work!

      Reply
    • March 31, 2010 at 7:20 pm
      Permalink

      Good afternoon, This is a superb blog, and Allow me to agree with what was composed here. I will be back to see the comments soon. Thanks

      Reply
    • November 23, 2010 at 3:33 am
      Permalink

      Hi,

      Thanks for this amazing post! I have some questions about tweaking it a bit though.

      Just recently started the transition from AS2 to AS3 so I’m fairly new to the language.

      First things first. Are there any ways to accomplish this with AS2? Mainly because an update to existing sites/projects already created in AS2 would be great. I’ve had a hard time to find AS2 examples.

      1. If I’d like to have this widget pull up tweets when it starts, instead of starting blank, how do I edit the code? Lets say I’d start of with the search string “I love NY” upon start?

      2. How to implement buttons with ‘search-strings’ in the widget? Lets say button A has the words “green giant washington” and button B has the words “flawless alligator escapes”.

      3. Where is the parameter to position the twitter result text field located within the code?

      4. There seem to be a problem to show some characters in the twitter posts, in my case scandinavian umlauts (å,ä,æ,ö,ø). Any suggestions why?

      5. You mention the twitter search limitation (I think it is 150 searches per hour) for high traffic websites. Reality is that it’s not that hard to reach those numbers on an average site as well. Every time the page with the twitter widget is reloaded a new request is sent out. Do you have other suggestions to alternative suggestions?

      Thanks for a great blog, Manuel

      Reply
      • November 23, 2010 at 11:06 am
        Permalink

        Hi Dave,

        I’m sorry to hear you are stuck in AS2 land, but I’m glad you are making the transition to AS3. I’m not aware of an AS2 library that is readily available for you to implement into your current projects. To keep the whole project in AS2, I would recommend you use a different approach. As you may know by now, even if you altered the code above to your likings, you would not be able to use the AS3 approach, due to the issues of loading an AS3swf into an AS2swf, Google it. Tho, not the end of the world, you could probably come up with a wonky solution using Local Connection, but I wouldn’t advise it. Instead I’m going to push you in a new direction, one that requires Flash to communicate with PHP. That way you can use your AS2 knowledge to load in php results. There are tons of Flash to PHP communication on the interwebs, fire up a Google search.

        Here’s a link to Ryan Faermans blog post on a php solution to search twitter : http://ryanfaerman.com/twittersearch/. You could easily alter his code to return the search values to flash. You could probably find tons more of php related Twitter functionality. As I mentioned in my post you will end up hitting Twitters query limit, and have to start looking for a proxy approach, so you might as well go down that road now. At this point I’m not sure if the questions you asked are relevant now, but here a few quick answers:

        (1) Easy, update the _currentSearchKeyword variable and call the searchTwitter() method in the constructor like so:

        public function Main() {

        _content = new Sprite();
        _content.x = 20;
        _content.y = 65;
        addChild(_content);
        _searchButton = sButton;
        _searchInput = sInput;
        _searchInput.text = _currentSearchKeyword;
        _twtr = new Tweetr();
        addSearchFormListeners();
        //update the search var
        _currentSearchKeyword = “I love NY”;
        //call the method
        searchTwitter();

        }

        (2) You could do this 2 ways: 1- create a new method call addSearchButton() and add the button listeners to it or 2- add to existing method addSearchFormListeners()

        private function addSearchFormListeners():void {
        _searchButton.addEventListener(MouseEvent.CLICK, startTwitterSearch);
        _searchButton.enabled = true;
        _searchInput.addEventListener(Event.CHANGE,updateSearchKeywords);
        _searchInput.enabled = true;
        // add new buttons
        _buttonOne.addEventListener(MouseEvent.CLICK, buttonOneStartTwitterSearch);//the listener which detects the on click mouse event
        _buttonOne.enabled = true;//make sure the button is enabled or clickable
        _buttonTwo.addEventListener(MouseEvent.CLICK, buttonTwoStartTwitterSearch);
        _buttonTwo.enabled = true;
        //keep adding your desired number of buttons
        }

        oh and revise the removeSearchFormListeners() method to remove the the listeners – just good coding practice

        private function removeSearchFormListeners():void {
        _searchButton.removeEventListener(MouseEvent.CLICK, startTwitterSearch);
        _searchButton.enabled = false;
        _searchInput.removeEventListener(Event.CHANGE,updateSearchKeywords);
        _searchInput.enabled = false;
        //
        _buttonOne.removeEventListener(MouseEvent.CLICK, buttonOneStartTwitterSearch);
        _buttonOne.enabled = false;
        _buttonTwo.removeEventListener(MouseEvent.CLICK, buttonTwoStartTwitterSearch);
        _buttonTwo.enabled = false;
        //ect..ect.

        }

        and then add the 2 methods which those buttons call. The methods basically updates the search keyword and calls the searchTwitter() method

        //method for button one

        private function buttonOneStartTwitterSearch(event:MouseEvent):void {
        _currentSearchKeyword = “green giant washington”;
        searchTwitter();
        }

        and

        //method for button 2

        private function buttonOneStartTwitterSearch(event:MouseEvent):void {
        _currentSearchKeyword = “flawless alligator escapes”;
        searchTwitter();
        }

        (3) So when ever Twitter responds with results the onCompleteHandler() method is called. If you review the method you will notice that it:

        var sXml:XML = new XML(event.data);//receives the data in xml format
        _searchArray = DataParser.parseSearchResults(sXml);//parses the data into an array of objects
        createTweetPanel(_searchArray);//and then creates the Tweet Panel

        In the createTweetPanel() method you will notice that I build the actual panel using an object in the library – new TweetPanel().
        then I add it to stage like so:
        _content.addChild(tn); // which basically states to add the thumbnail object into the content Sprite – the equivalent in as2 is attach movieclip

        Now you will notice that _content sprite is in the constructor which is where I actually do the placement:

        _content.x = 20;
        _content.y = 65;

        So to move it around, just revise the numbers.

        (4) Fonts is the reason why. You need to embed a font which handles the umlauts.

        (5) Use a proxy. If I ever get around to it, I will post it for all to see. I need to get a blessing from my Php guru before I release it.
        In a nutshell this is what it does:

        Flash calls the proxy passing a query string (search string). Php checks a results folder to see if a file exists with the search name (“earthday.txt”), if a file does exist it checks a time stamp to determine how old the file is, if its relatively new, it reads the text files content and returns the results to flash. If its real old, it removes the file and makes a new call to Twitter, returns the results to flash and writes the file to the results folder (caching).

        If a file does not exist it makes a call to Twitter, returns the results to flash and writes the file to the results folder with a timestamp.

        Anyhow good luck, and I hope this helps.

        M

        Reply
    • October 30, 2012 at 2:20 pm
      Permalink

      Hi,
      first, thanks this app works great!, I just have some questions to ask, how can I reduce the update time for tweets? and is possible to run the app without the search button?,

      Again, thanks a lot.
      Greettings

      Reply

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    %d bloggers like this: