Downloading PDC10 videos using the new async feature

I knew PDC10 has an OData endpoint which is http://odata.microsoftpdc.com/ODataSchedule.svc/ . The best part about  OData is querying for specific data that we are looking for. And here is my OData url for filtering twitter hashtag #languages


http://odata.microsoftpdc.com/ODataSchedule.svc/Sessions()?$filter=startswith(TwitterHashtag,'%23languages')&$expand=DownloadableContent&$select=DownloadableContent

With the above OData feed I could get urls for low bandwidth mp4’s that I can download. And here is the sample code for filtering


var x =XDocument.Load(@"c:tempsession.xml").Descendants().AsParallel().Where(xd => xd.Name.LocalName=="Url"
&& xd.Value.Contains("_Low.mp4")).Select (xd => xd.Value);

Now that I have the url’s ,here is the code to download the videos using the new async feature

using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace Test
{
 class Foo
 {
 static void Main(string[] args)
 {
 DownloadAsync();
 Console.Read();
 }
 static async void DownloadAsync()
 {
 var result = new WebClient().DownloadStringTaskAsync("http://odata.microsoftpdc.com/ODataSchedule.svc/Sessions()?$filter=startswith(TwitterHashtag,'%23languages')&$expand=DownloadableContent&$select=DownloadableContent");
 var downloads = XDocument.Parse(await result).Descendants().AsParallel().
 Where(xd => xd.Name.LocalName == "Url" && xd.Value.Contains("_Low.mp4")).
 Select(xd => new WebClient().DownloadFileTaskAsync(xd.Value, Path.GetFileName(xd.Value)));
 await TaskEx.WhenAll(downloads).ContinueWith(_ => Console.WriteLine("Downloading Complete"));
 }
 }
}
 

Combining Stack Overflow RSS, OData and API to query

In my opinion Stack Overflow has a ton of knowledge to learn new tricks. And there are some really smart people in the SO community. I try and learn new things when I find time.

I subscribe to RSS feeds for new questions on a particular topic. Example, here is one for F# from Stack Overflow http://stackoverflow.com/feeds/tag/f%23. The advantage of the RSS feed is I get to see new questions, but the drawback is I would have to navigate to the site to look for answers. AFAIK the stacky (stack overflow API) does not provide a mechanism for querying new questions based on a tag.

It was easy for me to combine both of them to solve my problem. With RSS feed I could discover new questions and with the stacky I could get answers . And I use Linqpad as a scratchpad so it was easy to write-up something quick.


void Main()
{
 var reader = XmlReader.Create("http://stackoverflow.com/feeds/tag/f%23");
 var feed = SyndicationFeed.Load<SyndicationFeed>(reader);
 var length = "http://stackoverflow.com/questions/".Length;

 var client = new StackyClient("1.0", File.ReadAllText(@"c:tempso.txt"),HostSite.StackOverflow,new UrlClient(), new JsonProtocol());

 var feedItems = from item in feed.Items
                 let nextOccurence = item.Id.ToString().IndexOf("/",length)
                 let getId = new Func<int>(() => Convert.ToInt32( item.Id.Substring(length,nextOccurence - length)))
                 select new {Id = getId(), Title = item.Title.Text, Body = item.Summary.Text.StripHTML()};

 var answers = client.GetQuestionAnswers(feedItems.Select (y => y.Id),new AnswerOptions() { IncludeBody = true});

 // The latest F# feed questions and answers
 var qa = from question in feedItems
          join answer in answers on question.Id equals answer.QuestionId
          where answer.Accepted == true
          select new { Title = question.Title, Question = question.Body.StripHTML(), Answer = answer.Body.StripHTML()};
 qa.Dump();
}
public static class Extensions
{
      public static string StripHTML(this string s)
      {
         return Regex.Replace(s, @"<(.|n)*?>", string.Empty);
      }
}

And if you have been following F# and functional programming then you would probably know Tomas. I would also like to read what he has been answering. Again stacky does not provide an API to query user by name. This is where the SO OData comes in handy and LinqPad handles OData very well. Here is the code to get Tomas user id via OData and query for questions and answers which he has answered using stacky .

var tomas = Users.Where(u => u.DisplayName.StartsWith("Tomas Pet")).First().Id;
var tomasQA = from ans in  client.GetUsersAnswers(tomas,new AnswerOptions() { IncludeBody = true })
              select new { Title = ans.Title, Question = client.GetQuestion(ans.QuestionId,true,false).Body.StripHTML(),
              Answer = ans.Body.StripHTML()};
tomasQA.Dump();
 

Using Tech-Ed OData to download videos

I wanted to watch the Teched 2010 videos, but the problem I had was going to the site manually to download files for offline viewing.  And I was also interested only in Dev sessions which were level 300 / 400. Thanks to OData for teched http://odata.msteched.com/sessions.svc/ ,I  could write 3 statements in linqpad and had them all downloaded using wget

File.Delete(@"C:tempdownload.txt");

Sessions
.Where (s => (s.Level.StartsWith("400") ||  s.Level.StartsWith("300") ) && s.Code.StartsWith("DEV"))
.Take(10)
.ToList()
.Select (s => @"http://ecn.channel9.msdn.com/o9/te/NorthAmerica/2010/mp4/" + s.Code + ".mp4" )
.Run(s => File.AppendAllText(@"C:tempdownload.txt",s + Environment.NewLine));

Util.Cmd(@"wget.exe -b -i c:Tempdownload.txt",true);

Forgot to mention for the Run extension method is from Reactive Extensions