Using OAuth to Send Updates to Twitter Using C#

Well I'm not sure if it's better. To be honest it's a bit more difficult to set up initially but it's a bit more secure than the way I showed before. Anyway, this year (in fact early this year), Twitter started a transition to using OAuth. Since I'm new to messing with the service, I had no idea. But then again I'm pretty oblivious to most things, so I might have missed that information even if I had been an early adopter. That being said, I've talked about OAuth before and I'll assume that you've read the post here. If not take a look before looking at the code below. Anyway, enough stalling, let's jump into some code:

/*
Copyright (c) 2009 <a href="http://www.gutgames.com">James Craig</a>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/


#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Utilities.Web.OAuth;
using System.Text.RegularExpressions;
using System.Web;
#endregion

namespace Utilities.Web.Twitter
{
    /// <summary>
    /// Helper class to deal with Twitter
    /// </summary>
    public class Twitter:OAuth.OAuth
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public Twitter()
            : base()
        {
            this.SignatureType = Signature.HMACSHA1;
        }

        #endregion

        #region Public Functions

        /// <summary>
        /// Gets a request token/token secret
        /// </summary>
        /// <param name="Token">The request token</param>
        /// <param name="TokenSecret">The request token secret</param>
        public void GetRequestToken(out string Token,out string TokenSecret)
        {
            this.Token = "";
            this.TokenSecret = "";
            this.Method = HTTPMethod.GET;
            this.Url = new Uri("http://twitter.com/oauth/request_token");
            REST.REST RestHelper = new Utilities.Web.REST.REST();
            RestHelper.Url = new Uri(GenerateRequest());
            string Value = RestHelper.GET();
            Regex TokenRegex = new Regex("oauth_token=(?<Value>[^&]*)");
            Match TempToken = TokenRegex.Match(Value);
            Token = TempToken.Groups["Value"].Value;
            Regex TokenSecretRegex = new Regex("oauth_token_secret=(?<Value>[^&]*)");
            Match TempTokenSecret = TokenSecretRegex.Match(Value);
            TokenSecret = TempTokenSecret.Groups["Value"].Value;
        }

        /// <summary>
        /// Gets the location of the authorization site (requires
        /// request token/token secret)
        /// </summary>
        /// <returns>The location that the user must go in order to
        /// authorize the app and get the authorization PIN</returns>
        public string GetAuthorizationSite()
        {
            this.Method = HTTPMethod.GET;
            this.Url = new Uri("http://twitter.com/oauth/authorize");
            this.AddParameter("oauth_callback", "oob");
            return new Uri(GenerateRequest()).ToString();
        }

        /// <summary>
        /// Gets the access token/token secret which are used in actual calls
        /// (requires the PIN from the authorization site and the request token
        /// and request token secret)
        /// </summary>
        /// <param name="PIN">PIN received from the authorization site</param>
        /// <param name="AccessToken">The access token</param>
        /// <param name="AccessTokenSecret">The access token secret</param>
        public void GetAccessToken(string PIN, out string AccessToken, out string AccessTokenSecret)
        {
            this.Url = new Uri("http://twitter.com/oauth/access_token");
            this.AddParameter("oauth_verifier", PIN);
            this.Method = HTTPMethod.POST;
            REST.REST RestHelper = new Utilities.Web.REST.REST();
            RestHelper.Url = new Uri(GenerateRequest());
            string Value = RestHelper.POST();
            Regex TokenRegex = new Regex("oauth_token=(?<Value>[^&]*)");
            Match TempToken = TokenRegex.Match(Value);
            AccessToken = TempToken.Groups["Value"].Value;
            Regex TokenSecretRegex = new Regex("oauth_token_secret=(?<Value>[^&]*)");
            Match TempTokenSecret = TokenSecretRegex.Match(Value);
            AccessTokenSecret = TempTokenSecret.Groups["Value"].Value;
        }

        /// <summary>
        /// Updates the status of the user
        /// </summary>
        /// <param name="Status">Status of the user (needs to be within 140 characters)</param>
        /// <returns>The XML doc returned from the Twitter service</returns>
        public string UpdateStatus(string Status)
        {
            this.Method = HTTPMethod.POST;
            this.Url = new Uri("http://twitter.com/statuses/update.xml");
            this.AddParameter("status", Status);
            REST.REST RestHelper = new Utilities.Web.REST.REST();
            RestHelper.Url = new Uri(GenerateRequest());
            return RestHelper.POST();
        }

        /// <summary>
        /// Gets a user's timeline from the Twitter service
        /// </summary>
        /// <param name="UserName">The screen name of the user</param>
        /// <returns>The XML doc returned from the Twitter service
        /// contatining the timeline</returns>
        public string GetTimeline(string UserName)
        {
            this.Method = HTTPMethod.POST;
            this.Url = new Uri("http://twitter.com/statuses/user_timeline.xml");
            this.AddParameter("screen_name", UserName);
            REST.REST RestHelper = new Utilities.Web.REST.REST();
            RestHelper.Url = new Uri(GenerateRequest());
            return RestHelper.GET();
        }

        #endregion
    }
}

The code above uses the OAuth helper class (modified, from the post that I link to so go to the svn store on codeplex to see the latest version) along with a new REST helper class that I created to work with Twitter. But before I show the REST class, I should explain the code above. There are a number of functions here that you need to call prior to ever being able to send anything to Twitter. The first is GetRequestToken. This does what it sounds like. It gets a request token from the Twitter service. The request token is then used to register an app with a user. Prior to authorizing the app, you can't do a damn thing when using OAuth. The request token/token secret that is returned by the Twitter service are then used in the GetAuthorizationSite function. This function simply gets you the location that the user must go in order to authorize your app to work with their account. The user goes to that location, clicks on Allow and is then given a PIN number. Note that during all of this you have to hold onto the request token/secret token so that you can use them along with the PIN in the next function: GetAccessToken. This function actually trades in the request token that you're using for an access token/token secret. These are then used in all of the functions that actually do anything...

That's right, you just went through three steps just so you can start to use the service. It's annoying but on the bright side, it's much more secure. Not to mention it tends to make those who are paranoid trust you a bit more as they are no longer giving you their user name and password. Anyway, the other two functions in the class do two things. The first is a status update function. It's basically what I showed you before in the previous post but cleaned up and using OAuth instead of basic authentication. The second function allows you to query Twitter for a timeline of a single user. It returns an XML file that you'll need to parse, but it does get the job done for now. They should be fairly simple to follow... Well, they would be if I had shown you the REST class before now. So you're not completely confused here it is:

/*
Copyright (c) 2009 <a href="http://www.gutgames.com">James Craig</a>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/


#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
#endregion

namespace Utilities.Web.REST
{
    /// <summary>
    /// Class designed to help with calling REST based applications
    /// </summary>
    public class REST
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public REST()
        {
        }

        #endregion

        #region Public Functions

        /// <summary>
        /// Does a GET to the REST service
        /// </summary>
        /// <returns>a string containing the data returned by the service</returns>
        public string GET()
        {
            try
            {
                HttpWebRequest Request = WebRequest.Create(Url) as HttpWebRequest;
                Request.Method = "GET";
                Request.ContentType = "text/xml";
                SetupData(Request);
                SetupCredentials(Request);
                return SendRequest(Request);
            }
            catch { throw; }
        }

        /// <summary>
        /// Does a POST to the REST service
        /// </summary>
        /// <returns>a string containing the data returned by the service</returns>
        public string POST()
        {
            try
            {
                HttpWebRequest Request = WebRequest.Create(Url) as HttpWebRequest;
                Request.Method = "POST";
                Request.ContentType = "application/x-www-form-urlencoded";
                SetupData(Request);
                SetupCredentials(Request);
                return SendRequest(Request);
            }
            catch { throw; }
        }

        /// <summary>
        /// Does a DELETE on the REST service
        /// </summary>
        /// <returns>a string containing the data returned by the service</returns>
        public string DELETE()
        {
            try
            {
                HttpWebRequest Request = WebRequest.Create(Url) as HttpWebRequest;
                Request.Method = "DELETE";
                Request.ContentType = "application/x-www-form-urlencoded";
                SetupData(Request);
                SetupCredentials(Request);
                return SendRequest(Request);
            }
            catch { throw; }
        }

        /// <summary>
        /// Does a PUT on the REST service
        /// </summary>
        /// <returns>a string containing the data returned by the service</returns>
        public string PUT()
        {
            try
            {
                HttpWebRequest Request = WebRequest.Create(Url) as HttpWebRequest;
                Request.Method = "PUT";
                Request.ContentType = "application/x-www-form-urlencoded";
                SetupData(Request);
                SetupCredentials(Request);
                return SendRequest(Request);
            }
            catch { throw; }
        }

        #endregion

        #region Private Functions

        /// <summary>
        /// Sets up any data that needs to be sent
        /// </summary>
        /// <param name="Request">The web request object</param>
        private void SetupData(HttpWebRequest Request)
        {
            if (string.IsNullOrEmpty(Data))
            {
                Request.ContentLength = 0;
                return;
            }
            try
            {
                byte[] ByteData = UTF8Encoding.UTF8.GetBytes(Data);
                Request.ContentLength = ByteData.Length;
                using (Stream RequestStream = Request.GetRequestStream())
                {
                    RequestStream.Write(ByteData, 0, ByteData.Length);
                }
            }
            catch { throw; }
        }

        /// <summary>
        /// Sets up any credentials (basic authentication,
        /// for OAuth, please use the OAuth class to create the
        /// URL)
        /// </summary>
        /// <param name="Request">The web request object</param>
        private void SetupCredentials(HttpWebRequest Request)
        {
            try
            {
                if (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password))
                {
                    Request.Credentials = new NetworkCredential(UserName, Password);
                }
            }
            catch { throw; }
        }

        /// <summary>
        /// Sends the request to the URL specified
        /// </summary>
        /// <param name="Request">The web request object</param>
        /// <returns>The string returned by the service</returns>
        private string SendRequest(HttpWebRequest Request)
        {
            try
            {
                using (HttpWebResponse Response = Request.GetResponse() as HttpWebResponse)
                {
                    if (Response.StatusCode != HttpStatusCode.OK)
                        throw new Exception("The request did not complete successfully and returned status code " + Response.StatusCode);
                    using (StreamReader Reader = new StreamReader(Response.GetResponseStream()))
                    {
                        return Reader.ReadToEnd();
                    }
                }
            }
            catch { throw; }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// URL to send the request to
        /// </summary>
        public Uri Url { get; set; }

        /// <summary>
        /// Any data that needs to be appended to the request
        /// </summary>
        public string Data { get; set; }

        /// <summary>
        /// User name (basic authentication)
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// Password (basic authentication)
        /// </summary>
        public string Password { get; set; }

        #endregion
    }
}

If you've ever dealt with a REST API before, it's pretty basic. But more or less it's divided into four functions, GET, PUT, POST, DELETE. It also allows for basic authentication if you need it. But basically you just load up the URL, any data that needs to be appended, user name and password and call the appropriate function. It in turn returns anything that the server sends back. So there you go, basic REST helper and Twitter helper classes. It's not that difficult to build off of them, so take a look, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 12/9/2009 at 10:11 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Netflix Title Search in C#

I showed in my last post how to do a basic auto complete sort of functionality using Netflix. Today I'm expanding on that a bit and showing some basic search functionality. Using the OAuth class that I created as a base class, we can easily create a set of classes to pull information from Netflix.

    /// <summary>
    /// Helper class to be used with the Netflix API
    /// </summary>
    public class Netflix : OAuth.OAuth
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public Netflix()
            : base()
        {
            this.SignatureType = Signature.HMACSHA1;
        }

        #endregion

        #region Public Functions

        /// <summary>
        /// Calls netflix's auto complete function
        /// </summary>
        /// <param name="ConsumerKey">Consumer key</param>
        /// <param name="Term">Your search term</param>
        /// <returns>A list of possible matches</returns>
        public List<string> AutoComplete(string ConsumerKey, string Term)
        {
            List<string> Results = new List<string>();
            string Content = FileManager.GetFileContents(new Uri("http://api.netflix.com/catalog/titles/autocomplete?oauth_consumer_key=" + ConsumerKey + "&term=" + Term));
            XmlDocument Document = new XmlDocument();
            Document.LoadXml(Content);
            foreach (XmlNode Children in Document.ChildNodes)
            {
                if (Children.Name.Equals("autocomplete", StringComparison.CurrentCultureIgnoreCase))
                {
                    foreach (XmlNode Child in Children.ChildNodes)
                    {
                        if (Child.Name.Equals("autocomplete_item", StringComparison.CurrentCultureIgnoreCase))
                        {

                            foreach (XmlNode Title in Child.ChildNodes)
                            {
                                if (Title.Name.Equals("title", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    Results.Add(Title.Attributes["short"].Value);
                                }
                            }
                        }
                    }
                }
            }
            return Results; 
        }

        /// <summary>
        /// Title search
        /// </summary>
        /// <param name="ConsumerKey">Consumer key</param>
        /// <param name="ConsumerKeySecret">Consumer key secret</param>
        /// <param name="Term">Term to search for</param>
        /// <param name="MaxResults">Max results to return</param>
        /// <param name="StartIndex">The starting index</param>
        /// <returns>List of title information</returns>
        public Titles TitleSearch(string ConsumerKey, string ConsumerKeySecret, string Term, int MaxResults, int StartIndex)
        {
            AddParameter("term", Term);
            AddParameter("max_results", MaxResults.ToString());
            AddParameter("start_index", StartIndex.ToString());
            this.ConsumerKey = ConsumerKey;
            this.ConsumerKeySecret = ConsumerKeySecret;
            this.Token = "";
            this.TokenSecret = "";
            this.Method = HTTPMethod.GET;
            this.Url = new Uri("http://api.netflix.com/catalog/titles/");
            return new Titles(FileManager.GetFileContents(new Uri(GenerateRequest())));
        }

        /// <summary>
        /// Title synopsis
        /// </summary>
        /// <param name="ConsumerKey">Consumer key</param>
        /// <param name="ConsumerKeySecret">Consumer key secret</param>
        /// <param name="Title">Title to search for</param>
        /// <returns>The synopsis info</returns>
        public string TitleSynopsis(string ConsumerKey, string ConsumerKeySecret, Title Title)
        {
            this.ConsumerKey = ConsumerKey;
            this.ConsumerKeySecret = ConsumerKeySecret;
            this.Token = "";
            this.TokenSecret = "";
            this.Method = HTTPMethod.GET;
            this.Url = new Uri(Title.SynopsisLink);
            string Content = FileManager.GetFileContents(new Uri(GenerateRequest()));

            XmlDocument Document = new XmlDocument();
            Document.LoadXml(Content);
            foreach (XmlNode Children in Document.ChildNodes)
            {
                if (Children.Name.Equals("synopsis", StringComparison.CurrentCultureIgnoreCase))
                {
                    return Children.InnerText;
                }
            }

            return "";
        }

        /// <summary>
        /// Cast search
        /// </summary>
        /// <param name="ConsumerKey">Consumer key</param>
        /// <param name="ConsumerKeySecret">Consumer key secret</param>
        /// <param name="Title">Title to search for</param>
        /// <returns>List of people information</returns>
        public People CastLookup(string ConsumerKey, string ConsumerKeySecret, Title Title)
        {
            this.ConsumerKey = ConsumerKey;
            this.ConsumerKeySecret = ConsumerKeySecret;
            this.Token = "";
            this.TokenSecret = "";
            this.Method = HTTPMethod.GET;
            this.Url = new Uri(Title.CastLink);
            return new People(FileManager.GetFileContents(new Uri(GenerateRequest())));
        }

        /// <summary>
        /// Director search
        /// </summary>
        /// <param name="ConsumerKey">Consumer key</param>
        /// <param name="ConsumerKeySecret">Consumer key secret</param>
        /// <param name="Title">Title to search for</param>
        /// <returns>List of people information</returns>
        public People DirectorLookup(string ConsumerKey, string ConsumerKeySecret, Title Title)
        {
            this.ConsumerKey = ConsumerKey;
            this.ConsumerKeySecret = ConsumerKeySecret;
            this.Token = "";
            this.TokenSecret = "";
            this.Method = HTTPMethod.GET;
            this.Url = new Uri(Title.DirectorsLink);
            return new People(FileManager.GetFileContents(new Uri(GenerateRequest())));
        }

        /// <summary>
        /// Similar title search
        /// </summary>
        /// <param name="ConsumerKey">Consumer key</param>
        /// <param name="ConsumerKeySecret">Consumer key secret</param>
        /// <param name="Title">Title to use as our search base</param>
        /// <returns>List of title information</returns>
        public Titles SimilarTitles(string ConsumerKey, string ConsumerKeySecret, Title Title)
        {
            this.ConsumerKey = ConsumerKey;
            this.ConsumerKeySecret = ConsumerKeySecret;
            this.Token = "";
            this.TokenSecret = "";
            this.Method = HTTPMethod.GET;
            this.Url = new Uri(Title.SimilarTitleLink);
            return new Titles(FileManager.GetFileContents(new Uri(GenerateRequest())));
        }

        /// <summary>
        /// Formats available for the title
        /// </summary>
        /// <param name="ConsumerKey">Consumer key</param>
        /// <param name="ConsumerKeySecret">Consumer key secret</param>
        /// <param name="Title">Title to use as our search base</param>
        /// <returns>List of available formats</returns>
        public List<string> FormatsAvailable(string ConsumerKey, string ConsumerKeySecret, Title Title)
        {
            this.ConsumerKey = ConsumerKey;
            this.ConsumerKeySecret = ConsumerKeySecret;
            this.Token = "";
            this.TokenSecret = "";
            this.Method = HTTPMethod.GET;
            this.Url = new Uri(Title.FormatsAvailableLink);
            string Content = FileManager.GetFileContents(new Uri(GenerateRequest()));

            List<string> Results = new List<string>();
            XmlDocument Document = new XmlDocument();
            Document.LoadXml(Content);
            foreach (XmlNode Children in Document.ChildNodes)
            {
                if (Children.Name.Equals("delivery_formats", StringComparison.CurrentCultureIgnoreCase))
                {
                    foreach (XmlNode Child in Children.ChildNodes)
                    {
                        if (Child.Name.Equals("availability", StringComparison.CurrentCultureIgnoreCase))
                        {
                            foreach (XmlNode Category in Child.ChildNodes)
                            {
                                if (Category.Name.Equals("category", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    Results.Add(Category.Attributes["term"].Value);
                                }
                            }
                        }
                    }
                }
            }
            return Results;
        }

        #endregion
    }

The code above has a number of functions that can be used to pull information. The main function that you'd be interested in is TitleSearch. It takes your consumer key, secret, search term, starting index, etc. The consumer key and secret key can be retrieved by signing up at netflix's developer center. But with that function, a helper class (Titles) is used to parse the information and return it so that it can be used. That along with the other helpers can be found below:

    /// <summary>
    /// List of titles
    /// </summary>
    public class Titles
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="XMLContent">XML Content</param>
        public Titles(string XMLContent)
        {
            XmlDocument Document = new XmlDocument();
            Document.LoadXml(XMLContent);
            TitleList = new List<Title>();

            foreach (XmlNode Children in Document.ChildNodes)
            {
                if (Children.Name.Equals("catalog_titles", StringComparison.CurrentCultureIgnoreCase)
                    || Children.Name.Equals("similars", StringComparison.CurrentCultureIgnoreCase))
                {
                    foreach (XmlNode Child in Children.ChildNodes)
                    {
                        if (Child.Name.Equals("catalog_title", StringComparison.CurrentCultureIgnoreCase)
                            || Child.Name.Equals("similars_item", StringComparison.CurrentCultureIgnoreCase))
                        {
                            TitleList.Add(new Title((XmlElement)Child));
                        }
                        else if (Child.Name.Equals("number_of_results", StringComparison.CurrentCultureIgnoreCase))
                        {
                            NumberOfResults = int.Parse(Child.InnerText);
                        }
                        else if (Child.Name.Equals("start_index", StringComparison.CurrentCultureIgnoreCase))
                        {
                            StartIndex = int.Parse(Child.InnerText);
                        }
                        else if (Child.Name.Equals("results_per_page", StringComparison.CurrentCultureIgnoreCase))
                        {
                            ResultsPerPage = int.Parse(Child.InnerText);
                        }
                    }
                }
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Number of results
        /// </summary>
        public int NumberOfResults { get; set; }

        /// <summary>
        /// Start index
        /// </summary>
        public int StartIndex { get; set; }

        /// <summary>
        /// Results per page
        /// </summary>
        public int ResultsPerPage { get; set; }

        /// <summary>
        /// List of titles
        /// </summary>
        public List<Title> TitleList { get; set; }

        #endregion
    }

 

    /// <summary>
    /// Title information
    /// </summary>
    public class Title
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="Element">Title information</param>
        public Title(XmlElement Element)
        {
            Categories = new List<string>();
            foreach (XmlNode Children in Element.ChildNodes)
            {
                if (Children.Name.Equals("id", StringComparison.CurrentCultureIgnoreCase))
                {
                    ID = Children.InnerText;
                }
                else if (Children.Name.Equals("title", StringComparison.CurrentCultureIgnoreCase))
                {
                    TitleInformation = new TitleInformation((XmlElement)Children);
                }
                else if (Children.Name.Equals("box_art", StringComparison.CurrentCultureIgnoreCase))
                {
                    BoxArt = new BoxArt((XmlElement)Children);
                }
                else if (Children.Name.Equals("release_year", StringComparison.CurrentCultureIgnoreCase))
                {
                    ReleaseYear = Children.InnerText;
                }
                else if (Children.Name.Equals("runtime", StringComparison.CurrentCultureIgnoreCase))
                {
                    RunTime = int.Parse(Children.InnerText);
                }
                else if (Children.Name.Equals("average_rating", StringComparison.CurrentCultureIgnoreCase))
                {
                    AverageRating = double.Parse(Children.InnerText);
                }

                else if (Children.Name.Equals("category", StringComparison.CurrentCultureIgnoreCase))
                {
                    if (Children.Attributes["scheme"] != null
                        && (Children.Attributes["scheme"].Value.Equals("http://api.netflix.com/categories/mpaa_ratings",
                            StringComparison.CurrentCultureIgnoreCase)
                            || Children.Attributes["scheme"].Value.Equals("http://api.netflix.com/categories/tv_ratingss",
                            StringComparison.CurrentCultureIgnoreCase)))
                    {
                        Rating = Children.Attributes["label"].Value;
                    }
                    else if (Children.Attributes["scheme"].Value.Equals("http://api.netflix.com/categories/genres",
                        StringComparison.CurrentCultureIgnoreCase))
                    {
                        Categories.Add(Children.Attributes["label"].Value);
                    }
                }
                else if (Children.Name.Equals("link", StringComparison.CurrentCultureIgnoreCase))
                {
                    if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/titles/synopsis",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        SynopsisLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/people.cast",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        CastLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/people.directors",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        DirectorsLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/titles/format_availability",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        FormatsAvailableLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/titles/screen_formats",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        ScreenFormatsLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/titles/languages_and_audio",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        LanguagesLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/titles.similars",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        SimilarTitleLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("alternate",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                         this.NetflixWebPage= Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/titles.series",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        this.SeriesLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/programs",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        this.EpisodeLink = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catalog/titles/official_url",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        this.StudioWebPage = Children.Attributes["href"].Value;
                    }
                }
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Title ID
        /// </summary>
        public string ID { get; set; }

        /// <summary>
        /// Title information
        /// </summary>
        public TitleInformation TitleInformation { get; set; }

        /// <summary>
        /// Box artwork
        /// </summary>
        public BoxArt BoxArt { get; set; }

        /// <summary>
        /// Synopsis link
        /// </summary>
        public string SynopsisLink { get; set; }

        /// <summary>
        /// Year released
        /// </summary>
        public string ReleaseYear { get; set; }

        /// <summary>
        /// Average rating
        /// </summary>
        public string Rating { get; set; }

        /// <summary>
        /// list of categories
        /// </summary>
        public List<string> Categories { get; set; }

        /// <summary>
        /// Run time in seconds
        /// </summary>
        public int RunTime { get; set; }

        /// <summary>
        /// Link to cast information
        /// </summary>
        public string CastLink { get; set; }

        /// <summary>
        /// Link to directories information
        /// </summary>
        public string DirectorsLink { get; set; }

        /// <summary>
        /// Formats available link
        /// </summary>
        public string FormatsAvailableLink { get; set; }

        /// <summary>
        /// Screen formats available link
        /// </summary>
        public string ScreenFormatsLink { get; set; }

        /// <summary>
        /// Language information link
        /// </summary>
        public string LanguagesLink { get; set; }

        /// <summary>
        /// Average rating
        /// </summary>
        public double AverageRating { get; set; }

        /// <summary>
        /// Similar titles to this one link
        /// </summary>
        public string SimilarTitleLink { get; set; }

        /// <summary>
        /// Link to netflix webpage
        /// </summary>
        public string NetflixWebPage { get; set; }

        /// <summary>
        /// Link to studio web page
        /// </summary>
        public string StudioWebPage { get; set; }

        /// <summary>
        /// Link to awards
        /// </summary>
        public string Awards { get; set; }

        /// <summary>
        /// Link to bonus material
        /// </summary>
        public string BonusMaterial { get; set; }

        /// <summary>
        /// Link for series info
        /// </summary>
        public string SeriesLink { get; set; }

        /// <summary>
        /// Link for episodes
        /// </summary>
        public string EpisodeLink { get; set; }

        /// <summary>
        /// Season info link
        /// </summary>
        public string SeasonLink { get; set; }

        #endregion
    }

 

    /// <summary>
    /// Title information
    /// </summary>
    public class TitleInformation
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="Element">Element information</param>
        public TitleInformation(XmlElement Element)
        {
            if (Element.Attributes["short"] != null)
            {
                ShortName = Element.Attributes["short"].Value;
            }
            if (Element.Attributes["regular"] != null)
            {
                RegularName = Element.Attributes["regular"].Value;
            }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Short name
        /// </summary>
        public string ShortName { get; set; }

        /// <summary>
        /// Regular name
        /// </summary>
        public string RegularName { get; set; }

        #endregion
    }

 

    /// <summary>
    /// Box art information
    /// </summary>
    public class BoxArt
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="Element">Element information</param>
        public BoxArt(XmlElement Element)
        {
            if (Element.Attributes["small"] != null)
            {
                SmallPicture = Element.Attributes["small"].Value;
            }
            if (Element.Attributes["medium"] != null)
            {
                MediumPicture = Element.Attributes["medium"].Value;
            }
            if (Element.Attributes["large"] != null)
            {
                LargePicture = Element.Attributes["large"].Value;
            }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Small picture
        /// </summary>
        public string SmallPicture { get; set; }

        /// <summary>
        /// Medium picture
        /// </summary>
        public string MediumPicture { get; set; }

        /// <summary>
        /// Large picture
        /// </summary>
        public string LargePicture { get; set; }

        #endregion
    }

 

    /// <summary>
    /// People list
    /// </summary>
    public class People
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="XMLContent">XML content</param>
        public People(string XMLContent)
        {
            XmlDocument Document = new XmlDocument();
            Document.LoadXml(XMLContent);
            PeopleList = new List<Person>();

            foreach (XmlNode Children in Document.ChildNodes)
            {
                if (Children.Name.Equals("people", StringComparison.CurrentCultureIgnoreCase))
                {
                    foreach (XmlNode Child in Children.ChildNodes)
                    {
                        if (Child.Name.Equals("person", StringComparison.CurrentCultureIgnoreCase))
                        {
                            PeopleList.Add(new Person((XmlElement)Child));
                        }
                        else if (Child.Name.Equals("number_of_results", StringComparison.CurrentCultureIgnoreCase))
                        {
                            NumberOfResults = int.Parse(Child.InnerText);
                        }
                        else if (Child.Name.Equals("start_index", StringComparison.CurrentCultureIgnoreCase))
                        {
                            StartIndex = int.Parse(Child.InnerText);
                        }
                        else if (Child.Name.Equals("results_per_page", StringComparison.CurrentCultureIgnoreCase))
                        {
                            ResultsPerPage = int.Parse(Child.InnerText);
                        }
                    }
                }
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// List of people
        /// </summary>
        public List<Person> PeopleList { get; set; }

        /// <summary>
        /// Number of results
        /// </summary>
        public int NumberOfResults { get; set; }

        /// <summary>
        /// Start index
        /// </summary>
        public int StartIndex { get; set; }

        /// <summary>
        /// Number of results per page
        /// </summary>
        public int ResultsPerPage { get; set; }

        #endregion
    }

 

    /// <summary>
    /// Person class
    /// </summary>
    public class Person
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="Element">person node</param>
        public Person(XmlElement Element)
        {
            foreach (XmlNode Children in Element.ChildNodes)
            {
                if (Children.Name.Equals("id", StringComparison.CurrentCultureIgnoreCase))
                {
                    ID = Children.InnerText;
                }
                else if (Children.Name.Equals("name", StringComparison.CurrentCultureIgnoreCase))
                {
                    Name = Children.InnerText;
                }
                else if (Children.Name.Equals("bio", StringComparison.CurrentCultureIgnoreCase))
                {
                    Bio = Children.InnerText;
                }
                else if (Children.Name.Equals("link", StringComparison.CurrentCultureIgnoreCase))
                {
                    if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("http://schemas.netflix.com/catlog/person/filmography",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        Filmography = Children.Attributes["href"].Value;
                    }
                    else if (Children.Attributes["rel"] != null
                        && Children.Attributes["rel"].Value.Equals("alternate",
                            StringComparison.CurrentCultureIgnoreCase))
                    {
                        Webpage = Children.Attributes["href"].Value;
                    }
                }
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// ID for the person
        /// </summary>
        public string ID { get; set; }

        /// <summary>
        /// Name of the person
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Bio information for the person
        /// </summary>
        public string Bio { get; set; }

        /// <summary>
        /// Filmography link
        /// </summary>
        public string Filmography { get; set; }

        /// <summary>
        /// Webpage link
        /// </summary>
        public string Webpage { get; set; }

        #endregion
    }

 

I realize that's a lot of code, but all it does is takes the XML that is returned and parses it out so that we can use the information. Most of the items are going to be rather obvious with one exception. Netflix doesn't return information directly in a normal search (well they can but it requires an extra couple of parameters). Instead what they do is they return a link that can be used for another query that will return that information. The reason for this is to save space. For instance, you may do a query and have 1000+ items returned. To save space, it's easier if you return the link instead of the whole description for a movie (or the cast, with all of their information, etc.).

So when you call TitleSearch, you're getting the basic information for the items and links to everything else that you would want. Which is why there are functions for things link pulling cast information, formats that it's available in, etc. As I said, we can actually have Netflix expand that information for us but once again I'd just go with the multiple queries unless it's information you know that you will need. Anyway, hopefully the code is of use to someone out there. So try it out, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 9/24/2009 at 9:27 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Auto Complete Search of the Netflix API in C#

In my last post I talked about OAuth and the fact that I was using it when dealing with the Netflix API. Well it turns out that not everything in the API requires OAuth. There is one portion of the API that requires very little (with the exception of a consumer key which you can get from the Netflix developer section). Specifically the auto complete functionality of the API. In order to do their auto complete search all you need is the consumer key and a search term. It gets fed to the system like OAuth does (a simple URL with the appropriate query string), but we don't have to deal with a signature, etc. So lets look at the code to get this done:

        public List<string> AutoComplete(string ConsumerKey, string Term)
        {
            List<string> Results = new List<string>();
            string Content = FileManager.GetFileContents(new Uri("http://api.netflix.com/catalog/titles/autocomplete?oauth_consumer_key=" + ConsumerKey + "&term=" + Term));
            XmlDocument Document = new XmlDocument();
            Document.LoadXml(Content);
            foreach (XmlNode Children in Document.ChildNodes)
            {
                if (Children.Name.Equals("autocomplete", StringComparison.CurrentCultureIgnoreCase))
                {
                    foreach (XmlNode Child in Children.ChildNodes)
                    {
                        if (Child.Name.Equals("autocomplete_item", StringComparison.CurrentCultureIgnoreCase))
                        {

                            foreach (XmlNode Title in Child.ChildNodes)
                            {
                                if (Title.Name.Equals("title", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    Results.Add(Title.Attributes["short"].Value);
                                }
                            }
                        }
                    }
                }
            }
            return Results;
        }

The code above does the call to the API using the FileManager class from my utility library. Once the response is read, it loads the XML that is returned and parses it, looking for the title content. I then put those values into a list of strings and return it. That's all there is to it really. So give it a try, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 9/22/2009 at 9:34 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed