I wanted to pull some data from YouTube above and beyond just what I could get from RSS.  In particular, one of the things I was hoping for was the ability to get at the http://search.yahoo.com/mrss/ namespace, which uses the media: tag prefix by convention.  Because the YouTube data is ATOM, I looked around for a good ATOM deserializer, but did find anything I really like until I came across the .NET Client Library for many of the Google services, which not only had great ATOM support, but also had a deserializer built for getting at the media: tags.  The getting started doc had me up and running quick and the developer's guide was real useful too.

Unfortunately, YouTube is not featured as a first class provider (yet) in the .NET libraries.  In order to get this working, I discovered that the Picasa libraries had support for consuming this namespace.  As such, I looked at the Picasa provider and was able to write my own very simple YouTube provider. I really like how the whole project is factored.  It made inheriting from the base classes real easy.  You can download the sample here.  The two GData .dlls are compiled from the 1.1.2.0 version of the GData .NET SDK. I've also posted the code below with some commentary if you are interested. Here's the code for my "client":

        static void Main(string[] args)  
        {
            FeedQuery query = new FeedQuery();
            query.Uri = new Uri("http://gdata.youtube.com/feeds/api/videos/-/chicken";);
            YouTubeService service = new YouTubeService("Microsoft-Flotzam-2", "yt");
            YouTubeFeed ytFeed = service.YouTubeQuery(query);
            foreach (YouTubeEntry yte in ytFeed.Entries)
            {
                Console.WriteLine(yte.Title.Text);
                Console.WriteLine("  " + yte.Media.Thumbnails[0].Attributes["url"]);

            }
            Console.ReadLine();
        }

Pretty straight forward.  I didn't have to override their query class since I'm not appending anything to the URL, but just getting lists of videos based on categories.

In order to get at that media: namespace, here's what I had to do. I made something called a YouTubeEntry that derived from AbstractEntry. And, within the YouTubeEntry, I was able to add the MediaRSS extensions in the ctor using their handy static class for registering to serialize that namespace.  I had to create my own YouTubeFeed class so that I could return a YouTubeEntry.  Then, I had to create my own YouTubeService so that I could return a strongly typed YouTubeFeed. Nice!  Here's the code:

    public class YouTubeService : Service  
    {  
        public YouTubeService(string application, string service)
            : base(application, service)
        {
            this.NewFeed += new ServiceEventHandler(this.OnNewFeed);
        }

        public YouTubeFeed YouTubeQuery(FeedQuery feedQuery)
        {
            return base.Query(feedQuery) as YouTubeFeed;
        }
        protected void OnNewFeed(object sender, ServiceEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            e.Feed = new YouTubeFeed(e.Uri, e.Service);
        }

    }
    public class YouTubeFeed : AbstractFeed
    {

        public YouTubeFeed(Uri uriBase, IService iService)
            : base(uriBase, iService)
        {
        }

        public override AtomEntry CreateFeedEntry()
        {
            return new YouTubeEntry();
        }
        protected override void HandleExtensionElements(ExtensionElementEventArgs e, AtomFeedParser parser)
        {
            base.HandleExtensionElements(e, parser);
        }
    }
    public class YouTubeEntry : AbstractEntry
    {  
        public YouTubeEntry()
        : base()
        {
            MediaRssExtensions.AddExtension(this);
        }
        public MediaGroup Media
        {
            get
            {  
                return FindExtension(MediaRssNameTable.MediaRssGroup,
                                     MediaRssNameTable.NSMediaRss) as MediaGroup;
            }
            set
            {  
                ReplaceExtension(MediaRssNameTable.MediaRssGroup,
                                MediaRssNameTable.NSMediaRss,
                                value);
            }
        }

    }