CSharp “How Do I Videos (Podcasts)” for the Zune Software

It can be handy to create custom RSS feeds for the Zune so that it is easy to download and watch selected videos. You can watch these videos either on your PC, or on the Zune itself. Here is a custom feed I created that contains all the new C# 4.0 language and IDE How Do I Videos, plus a selection of other How Do I videos. In total, at this time, there are 35 videos in the feed. The RSS I created uses a simple and quite minimal syntax tested only with Internet Explorer 8 and the software for Zune 4.0.740.0. The source for the C# program that generated the feed includes regular expressions, LINQ to Objects and LINQ to SQL. I discuss that program briefly at the bottom of this post.

You can use this custom feed from inside IE, as shown in Figure 0. However, I really created this feed to run on the Zune, so you should import the feed into the Zune software as a series of podcast. I explain this latter process in the next section of this post.

Figure00

Figure 0: Viewing a simple RSS feed in IE 8. Click the image to expand it.

Using the Feed in the Zune Software

In this section I provide a quick tutorial for those who’ve never used Podcasts with a Zune. Open the custom RSS feed in IE and grab the URL from the address bar. Alternately, you can just right click on any of the links to the feed in this document and choose Copy Shortcut or whatever the equivalent command is in Firefox or other browsers. Open the Zune software and turn to the Collection | Podcasts page. Click the button on the bottom left of the page called Add a Podcast. The Subscribe dialog appears. Paste in the URL for the feed, as shown in Figure 1, and then click the Subscribe button. The various How Do I podcasts included in the feed should begin downloading to your system, as shown in Figure 2.

Figure01 

Figure 1: Subscribing to an RSS Podcast feed in Zune Software 4.0.740.0 

Figure02

Figure 2: Viewing a feed in the Zune Software.

You can then plug in your Zune and right click on the feed and choose to sync the videos to your device. I’ll confess, however, that many of these videos look best on a PC, since you need a certain amount of screen real estate to adequately view the code typed in by the presenters.

Creating the RSS Feed by Screen Scrapping

I created this feed by the time honored hack of screen scraping. I first copied the URL for the home page of each video and passed it to C# code designed to download the HTML associated with the URL. The program parsed the HTML looking for the elements I needed in my feed. LINQ to XML provided a handy tool for creating my simple RSS feed. I simply passed in the data retrieved from the HTML file to a set of LINQ routines designed to produce the XML for an RSS feed.

This technique is simple to implement.  Screen scraping is nevertheless a very brittle practice, as my code will last only so long as the basic structure of the HTML pages that I’m parsing remains static. How long such conditions will prevail one can only suppose.

I called my quick and dirty program CreateRssFeed, and its source is available for download. The program is based on two custom classes, one for generating the RSS feed, the other for using Regular Expressions to parse the HTML file.  I store the URLs for the 35 HDI video pages in a file called UrlsToProcess.txt. I won’t bore you with the complete listings for this code, but I show the main body in Listing 1, and a short excerpt from the RSS feed is shown in Listing 2.

When you download the source, you will find versions for both VS 2008 and VS 2010, Beta 2. The latter solution contains both a console and a windows forms app. They each have their advantages, but I tend to prefer the former.

Listing 1: The main body of the program.

Code Snippet

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using CreateRssVideo.Code;
  5.  
  6. namespace CreateRssVideo
  7. {
  8.     class ProgramConsole
  9.     {
  10.         static void Main(string[] args)
  11.         {
  12.             string[] urls = File.ReadAllLines("UrlsToProcess.txt");
  13.             List<string> items = new List<string>();
  14.  
  15.             ParseHdiVideoPages parser = new ParseHdiVideoPages(items);            
  16.             foreach (var url in urls)
  17.             {
  18.                 parser.ProcessUrl(url);
  19.                 Console.WriteLine(items[items.Count-1]);
  20.             }
  21.  
  22.             File.WriteAllText(@"..\..\CSharpZuneReadyHowDoIVideos.rss", parser.RetrieveXml());
  23.         }
  24.     }
  25. }

 

Listing 1: An abbreviated version of the RSS Feed created by the code for the CreateRssVideo program.

Code Snippet

  1. <?xml version="1.0" encoding="utf-8" standalone="yes"?>
  2. <!--Charlie's RSS Feed for Videos-->
  3. <rss version="2.0">
  4.   <channel>
  5.     <title>CSharp How Do I Video Custom Feed for Zune Software</title>
  6.     <description>VS 2010 Related Videos</description>
  7.     <link>https://blogs.msdn.com/charlie</link>
  8.  
  9.     <item>
  10.       <title>Add Tool Windows to the Visual Studio IDE?</title>
  11.       <description>This video demonstrates how to</description>
  12.       <link>https://msdn.microsoft.com/en-us/vstudio/dd250814.aspx</link>
  13.       <enclosure url="https://download.microsoft.com/CreatingToolWindows.wmv" type="video/x-ms-wmv" />
  14.     </item>
  15.  
  16.   </channel>
  17. </rss>

The C# code for the CreateRssVideo program uses the build-in WebClient object to download the HTML for the video home page as a string:

 private static string RetrieveHtmlFromSite(string urlName)
{
    WebClient objWebClient = new WebClient();
    byte[] requestedUrl = objWebClient.DownloadData(urlName);
    UTF8Encoding utf8 = new UTF8Encoding();
    string htmlAsString = utf8.GetString(requestedUrl);
    return htmlAsString;
}

It then uses bits of Regular Expression code to parse the HTML and extract the title, description and video URL from it:

 private string FindStringInHtmlFile(string htmlAsString, string regEx)
{
    Regex r = new Regex(regEx, RegexOptions.IgnoreCase);

    MatchCollection matchCollection = r.Matches(htmlAsString);
    string groupItem = "";

    if (matchCollection.Count > 0)
    {
        foreach (Group groupItemFound in matchCollection[0].Groups)
        {
            groupItem = groupItemFound.Value;
        }
    }
    return groupItem;
}        

Below is a sample of one of the simple regular expressions that I pass into the FindStringInHtmlFile method. This particular bit of code is used to retrieve the description of the video from the HTML file:

 private static string regExDescriptionText = @"([A-Z\s0-9#\.,\(\)\-]+)";
private string regExDescription = @"<p><strong>About this Video</strong></p><p>" + regExDescriptionText;

While we are parsing the HTML, the program works step by step to create the RSS document using LINQ to XML. The first stage in the RSS creation is to new-up an outline or shell that will hold the meat of the document:

 public void Start()
{
    string link = "https://blogs.msdn.com/charlie";
    string title = "CSharp How Do I Video Custom Feed for Zune Software";
    string description = "VS 2010 Related Videos";

    theDocument = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
        new XComment("Charlie's RSS Feed for Videos"),
        GetChannel(link, title, description));
}        

private static XElement GetChannel(string link, string title, string description)
{
    return new XElement("rss", new XAttribute("version", "2.0"),
        new XElement("channel",
                        new XElement("title", title),
                        new XElement("description", description),
                        new XElement("link", link)));
}

The Start method creates the document itself, including an XML declaration and a comment. The GetChannel method adds a few simple fields to the document that describes its purpose and which list the URL for my home page. Compare this code with the first few lines from Listing 1 to be sure you understand its purpose.

As the information for each HDI video is discovered, a new <item> node is created for the RSS feed. This node lists the title for the video, describes the video, and references the URL for the HTML page where the video is stored. Finally, and most importantly, the code includes the <enclosure> node which stores the URL of the actual video. It is the <enclosure> node that the Zune software uses to locate the video which it downloads to your system:

 private static XElement GetItem(string itemTitle, string description, string linkUrl, string videoUrl)
{
    XElement item = new XElement("item",
                new XElement("title", itemTitle),
                new XElement("description", description),
                new XElement("link", linkUrl),
                new XElement("enclosure",
                    new XAttribute("url", videoUrl), new XAttribute("type", "video/x-ms-wmv")));
    return item;
}

Once the <item> node has been created, it is added to the XML document itself:

 public void AddItem(string itemTitle, string description, string linkUrl, string videoUrl)
{            
    XElement item = GetItem(itemTitle, description, linkUrl, videoUrl);            

    var linkNode = from x in theDocument.Descendants("link")
                   select x;
    
    linkNode.First().AddAfterSelf(item);            
}

Note that this code includes a simple LINQ query used to discover the proper insertion point in the XML document, and then employs the LINQ to XML AddAfterSelf operator to insert the new <item> XML node into the code for the RSS feed. The program enters and loop and repeats the process of creating and inserting <item> nodes into our RSS feed multiple times. Once all the URLs in our UrlsToProcess.txt document have been examined the program exits.

Summary

The primary purpose of this post is to provide an RSS feed that you can use to download videos for viewing in the Zune software or in the Zune itself. I also showed a simple, and very brittle, screen scraping program that I used to create the feed. I wrote this program for my own use, and pass it on to you with only minimal claims of its value. If nothing else, it provides some examples of how to have fun writing Regular Expressions, and demonstrates how easy it is to use LINQ to Objects and LINQ to XML to create XML documents.

kick it on DotNetKicks.com