Wednesday, April 9, 2014

Microsoft Build 2014 Session Conference Download


Die Build 2014 Konferenz ist ja vorüber, jetzt wäre es nett die Sessions im eigenen Wohnzimmer (noch einmal) Revue-passieren zu lassen.

Der Download der einzelnen Sessions findet ihr hier:
http://channel9.msdn.com/events/build/2014?wt.mc_id=build_hp

Natürlich ist das etwas mühsam, darum wäre doch ein kleines Download-Tool sehr praktisch, oder?
Da gibt es nun viele Möglichkeiten dies zu realisieren, angefangen bei einem PowerShell-Script und nicht enden wollend mit einer coolen WPF-App. Ich nehme den Mittelweg und stelle euch eine C# Command-Line-Applikation vor, die für uns den Download erledigt.

Zum Glück gibt es einen RSS-Feed mit den Sessions, diesen findet Ihr hier:
"http://channel9.msdn.com/Events/Build/2014/RSS/mp4";


Jetzt müssen wir noch eine kleine Applikation schreiben, die den RSS-Feed auswertet und uns die Dateien in einem Verzeichnis (z. B.: C:\Build2014) ablegt. Also nichts wie ran an den Speck, den Code findet Ihr nachfolgend. Das ganze sieht relativ unspektakulär aus, aber der Star sind hier auch die Sessions:


Für die Ungeduldigen unter euch gibt es den Download der fertigen Applikation, incl. Source findet hier: hier

Los geht's mit einer neuen Consolen-Applikation und der Main Methode:

static void Main(string[] args)
{
    Downloader d = new Downloader();
 
    var startTime = DateTime.Now;
 
    Console.WriteLine("Starting");
    Console.WriteLine(startTime);
 
    d.DownloadMedia();
 
    Console.WriteLine("Finished: " + DateTime.Now);
    Console.ReadLine();
 
}

Nun noch eine neue Klasse Downloader, zuvor fügt bitte noch die Referenz
zu System.ServiceModel hinzu:

Und es kann losgehen:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Authentication;
using System.ServiceModel.Syndication;
using System.Xml;
 
namespace ConferenceLoader
{
    public class Downloader
    {
        private const string ROOT_PATH = "C:\\Build2014\\";
        private const string MP4_FEED_URL = "http://channel9.msdn.com/Events/Build/2014/RSS/mp4";
        private Uri _feedUri;
        private char[] _invalidChars = { '\\''/'':''*''?''"''<''>''|' };
        private List<SessionInfo> _sessionInfoList;
        SyndicationFeed _feed;
 
        public Downloader()
        {
            this.Initialize();
        }
 
        public void DownloadMedia()
        {
            if (!CheckDirectory())
                return;
 
 
            DownloadAtom();
            ProcessAtomFeed();
            DownloadFiles();
        }
 
        private void DownloadFiles()
        {
            foreach (var sessionItem in this._sessionInfoList)
            {
 
                string destinationFileName = ComputeFileName(sessionItem.Title);
                bool fileExists = CheckIfFileExists(destinationFileName);
 
                if (fileExists)
                {
                    Console.WriteLine("File Exists: " + sessionItem.Title);
                }
                else
                {
                    Console.WriteLine("Downloading " + sessionItem.Title);
                    WebClient webClient = new WebClient();
                    webClient.DownloadFile(sessionItem.MediaUri, destinationFileName);
 
                }
            }
        }
 
        private string ComputeFileName(string sessionTitle)
        {
            var fileName = string.Empty;
            string fileNameTitle = ScrubSessionTitle(sessionTitle);
            fileName = ROOT_PATH + fileNameTitle + ".wmv";
            return fileName;
        }
 
        private bool CheckIfFileExists(string fileName)
        {
            return File.Exists(fileName);
        }
 
        private string ScrubSessionTitle(string sessionTitle)
        {
 
            var scrubbedString = sessionTitle;
            this._invalidChars.ToList().ForEach(x =>
            {
                scrubbedString = scrubbedString.Replace(x, ' ');
            });
 
            return scrubbedString;
 
        }
 
        private void ProcessAtomFeed()
        {
            foreach (var item in this._feed.Items)
            {
                var title = item.Title.Text;
                var uri = item.Links[1].Uri;
 
                this._sessionInfoList.Add(new SessionInfo
                    {
                        Title = title,
                        MediaUri = uri
 
                    });
 
            }
        }
 
        private void DownloadAtom()
        {
            XmlReader reader = XmlReader.Create(this._feedUri.ToString());
            this._feed = SyndicationFeed.Load(reader);
        }
 
 
        private void Initialize()
        {
            this._sessionInfoList = new List<SessionInfo>();
 
            SetFeedUri();
        }
 
        private bool CheckDirectory()
        {
            if (!Directory.Exists(ROOT_PATH))
            {
                Console.WriteLine(string.Format("Please create destination directory ({0}) first", ROOT_PATH));
                return false;
            }
            return true;
        }
 
        private void SetFeedUri()
        {
            string targetUrl = string.Empty;
            targetUrl = MP4_FEED_URL;
            this._feedUri = new Uri(targetUrl);
        }
 
    }
}

Am Ende noch eine kleine Klasse, die die Informationen über die Session hält:

public class SessionInfo
{
    public string Title { getset; }
    public Uri MediaUri { getset; }
}

Und das war es auch schon, ich wünsche euch viel Spass mit ca. 35GB an Videomaterial!
Der Code basiert auf er 2013er Version von hier

Bei Fragen, oder Anregungen meldet euch einfach bei mir!



CSharpCodeFormatter