Kotan Code 枯淡コード

In search of simple, elegant code

Menu Close

Consuming YouTube Feeds from Windows Phone 7

In my previous two blog posts, I talked about the mechanics of talking to simple Web Services on the web using the WebClient class and how you can parse that information. You can find those posts here and here. In this blog post, I’m going to create a class that you can use in your apps to consume feeds of published YouTube videos.

Basically I want to create a YouTubeManager class that I can just call a method on to go grab and parse a YouTube feed. I want to have the ability to extend this class in the future so that it can be used asynchronously in the background, so I’m going to use WebClient‘s DownloadStringAsync() method.

Here’s the code for my YouTubeManager class: (note that this is preliminary – the current design here doesn’t let you fetch more than one YouTube feed simultaneously):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Diagnostics;

namespace ExclaimComputing.ClientBranding.YouTube
{
 public static class YouTubeManager
 {
   private static Action<YouTubeVideoInfo[]> videoHandler;
   private static Action<Exception, object> videoFailHandler;

   public static void GetYouTubeFeed(
     string userName, Action<YouTubeVideoInfo[]> handler,
     Action<Exception,object> failHandler)
   {
   videoHandler = handler;
   videoFailHandler = failHandler;
   WebClient wc = new WebClient();
   wc.DownloadStringCompleted +=
     new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
   wc.DownloadStringAsync(
    new Uri("http://gdata.youtube.com/feeds/api/users/" +
    userName + "/uploads"));
   }

   static void wc_DownloadStringCompleted(object sender,
     DownloadStringCompletedEventArgs e)
   {
   if (e.Error != null)
   {
     videoFailHandler(e.Error, e.UserState);
   }
   else
   {
     Debug.WriteLine(e.Result);

     StringReader sr = new StringReader(e.Result);
     var reader = XmlReader.Create(sr);
     var document = XDocument.Load(reader);

     XNamespace atom = "http://www.w3.org/2005/Atom";
     var entries =
      from entry in document.Descendants(atom + "entry")
      let postedDate =
        DateTime.Parse(entry.Element(atom + "published").Value)
      orderby postedDate descending
      select new YouTubeVideoInfo()
      {
        PostedDate =
          DateTime.Parse(entry.Element(atom + "published").Value),
        Description = entry.Element(atom + "content").Value,
        Title = entry.Element(atom + "title").Value
      };

    videoHandler(entries.ToArray());
   }
   }
  }
}

Now that the manager (plumbing) code is taken care of, we can write our ViewModel class. An instance of our ViewModel class is to what the WP7 GUI will be bound. The following is a quick and dirty ViewModel class that invokes the manager to retrieve some videos:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;

namespace ExclaimComputing.ClientBranding.YouTube
{
 public class YouTubeViewModel : INotifyPropertyChanged
 {
 public YouTubeViewModel()
 {
   this.Items = new ObservableCollection<YouTubeVideoInfo>();

   YouTubeManager.GetYouTubeFeed(
     "????",
     //success handler
     videos =>
     {
       foreach (YouTubeVideoInfo videoInfo in videos)
       {
         this.Items.Add(videoInfo);
       }
     },
     // fail handler
     (exc, userState) =>
     {
       Debug.WriteLine(exc.ToString());
     }
   );
  }

  public ObservableCollection<YouTubeVideoInfo> Items { get; private set; }

  public event PropertyChangedEventHandler PropertyChanged;
  private void NotifyPropertyChanged(String propertyName)
  {
     PropertyChangedEventHandler handler = PropertyChanged;
     if (null != handler)
     {
       handler(this, new PropertyChangedEventArgs(propertyName));
     }
   }
 }
}

The NotifyPropertyChanged pattern is implemented in this view model out of habit – while I might start out just binding to the observable collection, past experience tells me that at some point I’m going to need to put a property on this thing. I have a code snippet for implementing INotifyPropertyChanged so it’s not that big of a deal.

In the preceding code, the “????” string should be replaced with the the username of the YouTube user whose uploads you want to obtain in this query.

A funny thing to note about the asynchronous wrapping pattern I’m using in my call to GetYouTubeFeed. It was inspired by how the new iOS4 SDK integrates blocks into many of the new API calls – allowing the developer to specify blocks of code to be executed at the completion of an asynchronous request. The beauty of this pattern is that even though what’s happening is asynchronous, I can still see all of the possible outcomes of this asynchronous request in the same area of the code. This makes my code easier to read and maintain and actually a lot easier to write.

Armed with the code from this blog post, it should be ridiculously easy now to integrate the consumption of YouTube video feeds into your WP7 application. Enjoy!