Blog

Tagged by 'youtube'

  • I've had a Spotify music membership for as long as I can remember. Many other subscriptions held throughout my life have come and gone, but Spotify has stood the test of time.

    A seed of doubt was planted when Spotify began raising the prices of their plans multiple times over a short period of time, beginning in April 2021. Even then, I was relatively unconcerned; it was annoying, but I felt content knowing there were no better music providers that could compete with what Spotify provided. Spotify made music very accessible to me in every way.

    During the first price hike, I trialled Apple Music during a brief period of insanity only to quickly come running back to the safety of Spotify.

    The penny dropped in May 2024, during the third price hike, when I began to question whether my Spotify usage was worth paying £11.99 per month. Even though I listen to music, I occasionally go through periods where I only listen to podcasts, which are freely available online and podcasting platforms.

    First Steps To Considering YouTube Music As A Viable Replacement

    Before making any hasty decisions, I audited all subscriptions both my wife and I use to if there is any possibility of making cost savings... Just like a Conservative party government imposing austerity measures, except my actions wouldn't lead to a Liz Truss level economic crises.

    It wasn't until I discovered my wife's YouTube Premium subscription, which she had purchased through the Apple App Store for an absurdly high price. A word to the wise: Never buy subscriptions through Apple's App Store because Apple charges a commission on top. My wife was paying around £18 per month compared to £12.99 if purchased directly from the YouTube website.

    I digress...

    This was enough to get me thinking about upgrading to the Family tier that included:

    • Ad-free videos
    • Offline downloads
    • YouTube Music
    • Add up to 5 members to the subscription

    All this costing £19.99 per month. At this price, we would be making savings if we moved away from our individual YouTube and Spotify plans. I was already sold on ad-free videos (those advertisements are so annoying!) and if I could be persuaded to subscribe to YouTube Music, this would end up being a very cost-effective option.

    The writing was on the wall. My Spotify days were numbered. I looked into what was involved (if possible) in migrating all my playlists over to YouTube Music.

    Requirements and Initial Thoughts of YouTube Music

    Prior to carrying out any form of migration, I opted for a 30 day free trial of YouTube Music as I wanted to see if it met as many key requirements as possible.

    Requirement Requirement Met?
    Availability of all songs from artists I listen to including the obscure ones Yes
    Podcasts Big yes
    Native MacOS app Room for improvement
    Ability to cast music to my speakers on my network Yes
    Quality new music suggestions Yes

    Overall, YouTube Music met majority of my requirements. As expected, it does take a little while to familiarise one self with the interface but there are similarities when compared with Spotify.

    YouTube Music - The Extension of YouTube

    YouTube Music is really an extension of YouTube in how it is able to pull in specific YouTube content, whether that is music videos, podcasts or shows. All the audio related content in video form you would normally view in YouTube is encompassed here. In most cases, this is seen as an advantage, however the only aspect where the lines between music and video get blurred is in the auto-generated "Liked music" playlist.

    You may find the "Liked music" playlist is already prefilled with videos you have liked on YouTube. If YouTube Music deems a liked video as music, it will also be shown here, which isn't necessarily accurate. For example, it automatically listed a Breaking Bad Parody video I liked from 9 years ago. If you prefer your randomly liked videos to stay in solely in YouTube, you have to manually disable the "Show your liked music from YouTube" feature in the settings.

    The Music Catalog and New Music Recommendations

    The music catalog size is on par with Spotify and there hasn't been a time where a track wasn't available. In fact, there were 3-4 tracks in my Spotify playlist that was no longer accessible, but this was not the case on YouTube Music, which was a surprise.

    During times when I am in the search for new music, I found the recommendation algorithm far better than Spotify and after a couple weeks of using YouTube Music I was compiled some really good personalised mixes - something that will get even better in time. Due to its link with YouTube, I was recommended even more options of live performances, remixes and cover tracks.

    What surprised me the most is the a feature I didn't even think I needed: The Offline Mixtape. There are times when I don't actually know what tracks I want to listen to when on the road and the Offline Mixtape compiles a list of tracks consisting of a combination of my liked songs and similar tracks for added variation. All automatically synchronised to my devices.

    Podcasts

    From the podcasts I listen to on Spotify I didn't have any issues in finding on YouTube Music. There is an added benefit of playing a podcast as audio or video (if the podcast offers this format), which is a nice touch. I was also recommended new types of podcasts that I would have never been exposed to based on what I listen to. I am sure (and correct me if I am wrong) Spotify didn't make recommendations as visible as what I am seeing in YouTube Music where podcasts are categorised. For example, the categories offered to me are: Wealth, Finances, Health, Mysteries, etc

    Lack of Native Desktop App

    The lack of a native desktop app detracts from my otherwise glowing review of YouTube Music. I was surprised to find that there isn't one, given that this is the norm among other music providers.

    Even though Chrome allows you to download it as a Progressive Web App, it's better than nothing. It just doesn't seem integrated enough. I keep accidentally closing the YouTube Music app on my MacOS by clicking the "close" button when all I want to do is hide the window.

    It can also be laggy at times, especially when Chromecasting to a smart speaker. When I change tracks, my speaker takes a few seconds to catch up.

    Overall, it's good but not great. Does not have the same polish as the Spotify app. But it's definitely manageable. The lack of a native desktop app has not dissuaded me from using it. If needed, I can always use the YouTube Music app on my Pixel or iPad.

    The Migration

    After a satisfactory trial period using YouTube Music, I looked for ways to move all my Spotify playlists. There are many options through online services and software that can aid the migration process, which can be used for free (sometimes with limitations) or at a cost.

    After carrying out some research on the various options available to me, I opted for a free CLI tool built in Python: spotify_to_ytmusic. It has received a lot of good reviews from a Reddit post and received positive feedback where users were able to migrate thousands of their songs spanning multiple playlists with ease. The only disadvantage with free options that provide unlimited migration is that they aren't necessarily straight-forward for the average user and some technical acumen is required.

    The installation, setup and familiarising yourself with the CLI commands to use the spotify_to_ytmusic application is the only part that takes some time. But once you have generated API Keys in both Spotify and Google, followed the instructions as detailed in the Github repo, the migration process itself doesn't take long at all.

    Conclusion

    When I told one of my coworkers that I had switched to YouTube Music, I received a sceptical look and a response to confirm I am of sane mind. This exemplifies how we have simply accepted Spotify as the only acceptable music platform, blinded to alternatives.

    YouTube Premium, which includes YouTube Music in one package, is an extremely good deal. Not only can you watch YouTube videos ad-free, but you also get a music library comparable to Spotify at a similar price.

    If you have been questioning whether YouTube Music is worth a try. Question no more and make the move.

  • It seems that I have a tendency to blog more about YouTube then any other Social API on this site. So here we go again... This time I want to show how to easily integrate a YouTube CMS Form Control within a Custom Table or Document Type within Kentico.

    As far as I'm aware, Kentico only allows you to insert YouTube markup into their HTML Editable Regions via the CKEditor. But what if you wanted to take things a step further and have the ability to return a video Title, Description and Thumbnail within the comfort of the Form tab?

    YouTube Custom CMS Form Control

    As you can see from my custom form control, a user would paste the URL of a YouTube video and press the "Lookup Video" button that will return basic information about that video, ready for the user to carry out any further copy changes they require.

    So let's get to it.

    Step 1: Create A New User Control

    I have created a user control in "/CMSFormControls/Surinder/" of my Kentico installation. I have named the user control: YouTubeLookup.ascx.

    HTML

    <table><tbody>	<tr>		<td class="TextColumn">			<label for="<%=YouTubeUrl.ClientID >">URL:</label> <asp:textbox id="YouTubeUrl" runat="server"></asp:textbox> <asp:button cssclass="ContentButton" id="LookupVideoDetail" onclick="LookupVideoDetail_Click" runat="server" text="Lookup Video"> </asp:button></td>	</tr>	<tr>		<td class="TextColumn">			<label for="<%=YouTubeTitle.ClientID >">Title:</label> <asp:textbox id="YouTubeTitle" runat="server" width="500"></asp:textbox></td>	</tr>	<tr>		<td class="TextColumn">			<label for="<%=YouTubeDescription.ClientID >">Description:</label> <asp:textbox height="100" id="YouTubeDescription" runat="server" textmode="MultiLine" width="500"></asp:textbox></td>	</tr>	<tr>		<td class="TextColumn">			<asp:image id="YouTubeThumbnail" runat="server"></asp:image></td>	</tr></tbody>
    </table>
    

    Code-behind

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using CMS.FormControls;
    using CMS.GlobalHelper;
    using System.Web.Script.Serialization;
    
    public partial class CMSFormControls_Surinder_YouTubeLookup : FormEngineUserControl
    {
        private string _jsonValue;
    
        public override Object Value
        {
            get
            {
                return GetJsonMarkup();
            }
            set
            {
                _jsonValue = System.Convert.ToString(value);
            }
        }
    
        private string GetJsonMarkup()
        {
            //Pass all user entered form values to the YouTubeDetail class for serialization in the JavaScriptSerializer
            if (!String.IsNullOrEmpty(YouTubeUrl.Text))
            {
                YouTubeDetail yt = new YouTubeDetail();
                yt.ID = YouTubeHelper.GetVideoID(YouTubeUrl.Text);
                yt.Title = YouTubeTitle.Text;
                yt.Description = YouTubeDescription.Text;
                yt.Url = YouTubeUrl.Text;
                yt.ImageUrl = YouTubeThumbnail.ImageUrl;
    
                JavaScriptSerializer jsSerialize = new JavaScriptSerializer();
    
                return jsSerialize.Serialize(yt);
            }
            else
            {
                return String.Empty;
            }
        }
    
        public override bool IsValid()
        {
            JavaScriptSerializer jsSerialize = new JavaScriptSerializer();
            var jsResult = jsSerialize.Deserialize<YoutubeDetail>(_jsonValue);
    
            if (jsResult != null && !String.IsNullOrEmpty(jsResult.ToString()))
            {
                if (String.IsNullOrEmpty(jsResult.Url))
                    return false;
                else
                    return true;
            }
            else
            {
                return true;
            }
        }
    
        protected void EnsureItems()
        {
            PopulateControls();
        }
    
        private void PopulateControls()
        {
            JavaScriptSerializer jsSerialize = new JavaScriptSerializer();
            var jsResult = jsSerialize.Deserialize<YoutubeDetail>(_jsonValue);
    
            //Check there if JSON is present to populate form controls
            if (jsResult != null && !String.IsNullOrEmpty(jsResult.ToString()))
            {
                if (!String.IsNullOrEmpty(jsResult.Url))
                    YouTubeUrl.Text = jsResult.Url;
    
                if (!String.IsNullOrEmpty(jsResult.Title))
                    YouTubeTitle.Text = jsResult.Title;
    
                if (!String.IsNullOrEmpty(jsResult.Description))
                    YouTubeDescription.Text = jsResult.Description;
    
                if (!String.IsNullOrEmpty(jsResult.ImageUrl))
                    YouTubeThumbnail.ImageUrl = jsResult.ImageUrl;
            }
        }
    
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
                EnsureItems();
        }
    
        protected void LookupVideoDetail_Click(object sender, EventArgs e)
        {
            //If YouTube URL is present, get the information
            if (!String.IsNullOrEmpty(YouTubeUrl.Text))
            {
                YouTubeDetail yt = YouTubeHelper.GetVideoInformation(YouTubeUrl.Text);
    
                if (yt != null)
                {
                    YouTubeTitle.Text = yt.Title;
                    YouTubeDescription.Text = yt.Description;
                    YouTubeThumbnail.ImageUrl = yt.ImageUrl;
                }
            }
        }
    }
    

    From looking at my code, you've probably noticed I'm actively using a "JavaScriptSerializer" to pass all my form values as JSON. I find this is the most straight-forward way to store multiple form values in a custom control. In this case, our values will be stored within a Kentico table column in the following format:

    {
        "ID":"fLyoog562x4",
        "Title":"How The Dark Knight Rises Should Have Ended",
        "Description":"Check out HISHE\u0027s spin on the epic conclusion to The Dark Knight Trilogy: How The Dark Knight Rises Should Have Ended.",
        "Url":"http://www.youtube.com/watch?v=fLyoog562x4",
        "ImageUrl":"http://i1.ytimg.com/vi/fLyoog562x4/hqdefault.jpg"
    }
    

    Whenever I need to get those values back, all I need to do is call the JavaScriptSerializer.Deserialize method.

    NOTE: If what I have shown doesn't make any sense, it'll be useful to take a look at an in-depth tutorial on how to create a Custom Form Control in Kentico: http://devnet.kentico.com/docs/devguide/index.html?developing_form_controls.htm

    Step 2: Create YouTubeDetail Class

    In order to serialize and deserialize values when using the JavaScriptSerializer, we need to create a class object with a number of properties to interpret the JSON structure.

    public class YouTubeDetail
    {
        public string ID { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string Url { get; set; }
        public string ImageUrl { get; set; }
    }
    

    Step 3: YouTube Methods

    This is the part when we start using Google's YouTube API and in order for this class to work, you will need to download the necessary DLL's. I suggest you take a gander at a post I wrote a while back called "Dynamically Output A List of YouTube Videos In ASP.NET" to get an in-depth introduction into using the YouTube API.

    To get data back from YouTube you will need as a minimum requirement the DLL's and register your application in order to pass an Application Name, Developer Key and Client ID values to your application.

    public class YouTubeHelper
    {
        private static string YouTubeDeveloperKey = WebConfigurationManager.AppSettings["YouTubeDeveloperKey"].ToString();
        private static string YouTubeAppName = WebConfigurationManager.AppSettings["YouTubeAppName"].ToString();
        private static string YouTubeClientID = WebConfigurationManager.AppSettings["YouTubeClientID"].ToString();
     
        //Get YouTube video
        public static Video YouTubeVideoEntry(string videoID)
        {
            YouTubeRequestSettings settings = new YouTubeRequestSettings(YouTubeAppName, YouTubeClientID, YouTubeDeveloperKey);
            YouTubeRequest request = new YouTubeRequest(settings);
     
            //Link to the feed we wish to read from
            string feedUrl = String.Format("http://gdata.youtube.com/feeds/api/videos/{0}", videoID);
     
            Feed<Video> videoFeed = request.Get<Video>(new Uri(feedUrl));
     
            return videoFeed.Entries.SingleOrDefault();
        }
     
        //Extract the YouTube ID from the web address.
        public static string GetVideoID(string videoUrl)
        {
            Uri tempUri = new Uri(videoUrl);
     
            string sQuery = tempUri.Query;
     
            return System.Web.HttpUtility.ParseQueryString(sQuery).Get("v");
        }
     
        //Get required YouTube video information
        public static YouTubeDetail GetVideoInformation(string url)
        {
            Video v = YouTubeVideoEntry(GetVideoID(url));
     
            //Pass required YouTube information to custom class called YouTubeDetail
            YouTubeDetail vDetail = new YouTubeDetail();
            vDetail.ID = v.VideoId;
            vDetail.Title = v.Title;
            vDetail.Description = v.Description;
            vDetail.ImageUrl = v.Thumbnails[2].Url;
    
            return vDetail;
        }
    
        //Output YouTube property within a document by passing the Document ID
        public static YouTubeDetail GetDocumentYouTubeValue(int docID)
        {
            TreeProvider tree = new TreeProvider();
            TreeNode tn = tree.SelectSingleDocument(docID);
    
            if (tn.GetValue("YouTube") != null && !String.IsNullOrEmpty(tn.GetValue("YouTube").ToString()))
            {
                JavaScriptSerializer jsSerialize = new JavaScriptSerializer();
                var jsResult = jsSerialize.Deserialize<YouTubeDetail>(tn.GetValue("YouTube").ToString());
    
                if (jsResult != null && !String.IsNullOrEmpty(jsResult.ToString()))
                {
                    return jsResult;
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }
    }
    

    Step 4: Add New Control Into Kentico

    Please refer to the Kentico Development Guide (as referenced in Step 1). The main thing you need to ensure is that the control can only be used as a "Long text" type.

    YouTube Kentico Control Settings

    Step 5: Outputting The YouTube Values To A Page

    Since we have stored all our YouTube fields in a JSON string, we can get those values out by carrying out a deserialization on our document type property.

    if (CMSContext.CurrentDocument.GetStringValue("YouTubeVideo", String.Empty) != String.Empty)
    {
        JavaScriptSerializer jsSerialize = new JavaScriptSerializer();
        YouTubeDetail yt = jsSerialize.Deserialize<YouTubeDetail>(CMSContext.CurrentDocument.GetStringValue("YouTubeVideo", String.Empty));
    
        YouTubeTitle.Text = yt.Title;
        YouTubeDescription.Text = yt.Description;
        YouTubeUrl.Text = yt.Url;
    }
    

    You may think I have slightly over-engineered the process to store YouTube video's. But if you have a website that is trying to push video content along with its META data, I believe this is the way to go.

  • Back in 2009 I wrote a simple web application to output all videos uploaded from a user’s channel. Luckily, hardly anything has changed. Now you only need to register for a Developer Key and state an Application Name. You are no longer required to provide a Client ID.

    This time round, I needed to output data onto my page from a single YouTube entry when a user pastes the URL of a YouTube video in one of my form fields.

    using System;
    using System.Linq;
    using System.Text;
    using Google.GData;
    using Google.YouTube;
    using Google.GData.Client;
    
    namespace MyProject.Helpers.Common
    {
        public class YouTubeHelper
        {
            private static string YouTubeDeveloperKey = WebConfigurationManager.AppSettings["YouTubeDeveloperKey"].ToString();
            private static string YouTubeAppName = WebConfigurationManager.AppSettings["YouTubeAppName"].ToString();
    
            //Get YouTube video
            public static Video YouTubeVideoEntry(string videoID)
            {
                YouTubeRequestSettings settings = new YouTubeRequestSettings(YouTubeAppName, YouTubeDeveloperKey);
                YouTubeRequest request = new YouTubeRequest(settings);
    
                //Link to the feed we wish to read from
                string feedUrl = String.Format("http://gdata.youtube.com/feeds/api/videos/{0}", videoID);
    
                Feed<Video> videoFeed = request.Get<Video>(new Uri(feedUrl));
    
                return videoFeed.Entries.SingleOrDefault();
            }
    
            //Extract the YouTube ID from the web address.
            public static string GetVideoID(string videoUrl)
            {
                Uri tempUri = new Uri(videoUrl); 
    
                string sQuery = tempUri.Query;
    
                return System.Web.HttpUtility.ParseQueryString(sQuery).Get("v");
            }
    
            //Get required YouTube video information
            public static YouTubeDetail GetVideoInformation(string url)
            {
                Video v = YouTubeVideoEntry(GetVideoID(url));
    
                //Pass required YouTube information to custom class called YouTubeDetail
                YouTubeDetail vDetail = new YouTubeDetail();
                vDetail.ID = v.VideoId;
                vDetail.Title = v.Title;
                vDetail.Description = v.Description;
    
                return vDetail;
            }
        }
    }
    

    Hopefully, my “YouTubeHelper” class is easy to follow. All you need to use is the “GetVideoInformation()” method by simply passing a page link to where your YouTube video resides. At the moment only full YouTube URL’s are accepted not the short URL (http://youtu.be/).

  • Ok! I admit it! I posted some incorrect information from one of my previous blog posts to “Dynamically Output A List of YouTube Video’s In ASP.NET”. I stupidly said: “The RSS feed is not structured in a nice enough format to output all the information you may need with ease.” I must have been drunk when I wrote that. As you can see from a sample of their RSS feed below I was wrong:

    <entry>
      <id>http://gdata.youtube.com/feeds/api/videos/R6r2ckeIpic</id>
        <published>2009-05-31T17:01:12.000Z</published>
        <updated>2009-06-01T01:22:11.000Z</updated>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='bike'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Podcast'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Pedrosa'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='motorcycles'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Honda+RC212V'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='speed'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Suzuki+GSV-R800'/>
        <category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat' term='Sports' label='Sport'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Rossi'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='motorcycle+road+racing'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='motograndprix'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Yamaha+YZR+M1'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Mugello'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Italy'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Stoner'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Ducati+Desmosedici+GP8'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='MotoGP'/>
        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Lorenzo'/>
        <title type='text'>MotoGP action from Mugello 2009</title>
        <content type='text'>The best of the action from the Gran Premio D&amp;#180;Italia Alice, the fifth round of the 2009 motogp World Championship.</content>
        <link rel='alternate' type='text/html' href='http://www.youtube.com/watch?v=R6r2ckeIpic'/>
        <link rel='http://gdata.youtube.com/schemas/2007#video.responses' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/R6r2ckeIpic/responses'/>
        <link rel='http://gdata.youtube.com/schemas/2007#video.related' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/R6r2ckeIpic/related'/>
        <link rel='self' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/users/motogp/uploads/R6r2ckeIpic'/>
        <author>
          <name>MotoGP</name>
          <uri>http://gdata.youtube.com/feeds/api/users/motogp</uri>
        </author>
        <gd:comments>
          <gd:feedLink href='http://gdata.youtube.com/feeds/api/videos/R6r2ckeIpic/comments' countHint='24'/>
        </gd:comments>
        <media:group>
          <media:category label='Sport' scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>Sports</media:category>
          <media:description type='plain'>The best of the action from the Gran Premio D&amp;#180;Italia Alice, the fifth round of the 2009 motogp World Championship.</media:description>
          <media:keywords>MotoGP, Italy, Mugello, Podcast, Stoner, Pedrosa, Rossi, Lorenzo, Yamaha+YZR+M1, Ducati+Desmosedici+GP8, Honda+RC212V, Suzuki+GSV-R800, motorcycle+road+racing, motograndprix, motorcycles, bike, speed</media:keywords>
          <media:player url='http://www.youtube.com/watch?v=R6r2ckeIpic'/>
          <media:thumbnail url='http://i.ytimg.com/vi/R6r2ckeIpic/2.jpg' height='90' width='120' time='00:00:38.500'/>
          <media:thumbnail url='http://i.ytimg.com/vi/R6r2ckeIpic/1.jpg' height='90' width='120' time='00:00:19.250'/>
          <media:thumbnail url='http://i.ytimg.com/vi/R6r2ckeIpic/3.jpg' height='90' width='120' time='00:00:57.750'/>
          <media:thumbnail url='http://i.ytimg.com/vi/R6r2ckeIpic/0.jpg' height='240' width='320' time='00:00:38.500'/>
          <media:title type='plain'>MotoGP action from Mugello 2009</media:title>
          <yt:duration seconds='77'/>
        </media:group>
        <yt:noembed/>
        <gd:rating average='4.862069' max='5' min='1' numRaters='29' rel='http://schemas.google.com/g/2005#overall'/>
        <yt:statistics favoriteCount='10' viewCount='1055'/>
    </entry>
    <entry>
        ...
    </entry>
    <entry>
        ...
    </entry>
    

    Each “entry” element within the RSS feed represents a YouTube video. You are able to extrapolate all the important information about each movie such as Average Score, View Count, Thumbnail Images, Video Description, etc. Really useful stuff!

    You may be thinking: Why should I use an RSS feed to retrieve the video information rather than using the YouTube API? Well, using a YouTube API is definitely the easier and most straight-forward method. But what you should be aware that the API only works from .NET 2.0 onwards. There isn’t a YouTube API for .NET 1.1. Unfortunately, I only found this out when I tried to implement the API into one of my .NET 1.1 client sites.

    The code I have written below, reads the YouTube RSS feed and stores the information in a DataTable.

    private void GetYouTubeData(string YouTubeUrl)
    {
        //Create DataTable to store specific YouTube information
        DataTable dtYouTubeVideoData = new DataTable();
        dtYouTubeVideoData.Columns.Add("YouTubeID");
        dtYouTubeVideoData.Columns.Add("Title");
        dtYouTubeVideoData.Columns.Add("Description");
        dtYouTubeVideoData.Columns.Add("ImageUrl");
        dtYouTubeVideoData.Columns.Add("AverageRatings");
        dtYouTubeVideoData.Columns.Add("ViewCount");
    
        DataRow drYouTubeVideoData;
    
        //Link to YouTube RSS feed
        XmlTextReader rssReader = new XmlTextReader(YouTubeUrl);
        XmlDocument xmlDoc = new XmlDocument();
    
        //Download the XML (via the XmlTextReader)
        xmlDoc.Load(rssReader);
    
        //Select all nodes starting with "entry"
        XmlNodeList xmlNodeList = xmlDoc.GetElementsByTagName("entry");
        
        //For each "entry" element found
        foreach (XmlNode node in xmlNodeList)
        {
            drYouTubeVideoData = dtYouTubeVideoData.NewRow();
    
            //Create a new document, to search through the inner contents
            XmlDocument innerXmlDocument = new XmlDocument();
            innerXmlDocument.LoadXml(node.OuterXml);
    
            // Get movie ID
            drYouTubeVideoData["YouTubeID"] = innerXmlDocument.GetElementsByTagName("id")[0].InnerText.Replace("http://gdata.youtube.com/feeds/api/videos/", "");
    
            // Get movie title
            drYouTubeVideoData["Title"] = innerXmlDocument.GetElementsByTagName("title")[0].InnerText;
    
            //Get movie description
            drYouTubeVideoData["Description"] = innerXmlDocument.GetElementsByTagName("content")[0].InnerText;
            
            //Get the thumbnails
            XmlNodeList mediaTumbnail = innerXmlDocument.GetElementsByTagName("media:thumbnail");
    
            //Iterate through each thumbnail and only get one thumbnail per <entry>.
            foreach (XmlNode thumbnailNode in mediaTumbnail)
            {
                if (thumbnailNode.Attributes["height"].Value == "90" && thumbnailNode.Attributes["url"].Value.EndsWith("1.jpg"))
                {
                    drYouTubeVideoData["ImageUrl"] = thumbnailNode.Attributes["url"].Value;
                }
            }
    
            //Get movie rating
            XmlNodeList ratings = innerXmlDocument.GetElementsByTagName("gd:rating");
    
            foreach (XmlNode ratingsNode in ratings)
            {
                drYouTubeVideoData["AverageRatings"] = ratingsNode.Attributes["average"].Value;
            }
    
            //Get Statistics
            XmlNodeList statistics = innerXmlDocument.GetElementsByTagName("yt:statistics");
    
            foreach (XmlNode statisticsNode in statistics)
            {
                drYouTubeVideoData["ViewCount"] = statisticsNode.Attributes["viewCount"].Value;
            }
    
            dtYouTubeVideoData.Rows.Add(drYouTubeVideoData);
        }
    
        rssReader.Close();
    
        //Bind YouTube data to repeater
        repVideoList.DataSource = dtYouTubeVideoData;
        repVideoList.DataBind();        
    }
    
  • I recently needed to dynamically display a list of YouTube video’s from a specific YouTube account. If you plan to output the list of video’s straight from the YouTube’s RSS feed into your .NET application don’t bother. The RSS feed is not structured in a nice enough format to output all the information you may need with ease. For example, video ratings, time, etc are all in the same XML block.

    As you can see from the screenshot below, the ASP.NET page I created outputs all the information that you will probably want to show (if it doesn’t then it should give you a good starting point).

    YouTubeReaderScreenshot

    Before creating your own custom YouTube .NET application you will need to carry out two things:

    1. Go to the YouTube API Toolswebsite and download the “Google Data API SDK”. Once you have installed this on your computer. You will need to copy three dll’s from one of the sample projects:

      • Google.GData.Client.dll
      • Google.GData.Extensions.dll
      • Google.GData.YouTube.dll

      These dll's can be copied to your new project.

    2. Register a Developer Key. This is important! Without the developer key, your custom YouTube application will not work.

    To create the page (above), copy the following code:

    ASPX.CS Page

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Xml;
    using System.Net;
    using System.IO;
    using System.Text.RegularExpressions;
    using Google.GData.Client;
    using Google.GData.Extensions;
    using Google.GData.Extensions.MediaRss;
    using Google.YouTube;
    using Google.GData.YouTube;
    using System.Text;
    using System.Data;
    
    public partial class _Default : System.Web.UI.Page
    {
        private string YouTubeChampionshipChannel;
        private string YouTubeClientID;
        private string YouTubeDeveloperKey;
        public string YouTubeMovieID;
        public DataTable dtVideoData = new DataTable();
    
        protected void Page_Load(object sender, EventArgs e)
        {
            //Pass User Name to the YouTube link
            YouTubeChampionshipChannel = "MotoGP";
    
            //Add the YouTube Developer keys.
            //Register a Developer Key at: http://code.google.com/apis/youtube/dashboard
            YouTubeClientID = "test";
            YouTubeDeveloperKey = "testabc123";
    
            CreateVideoFeed();
    
            //Assign the first video details on page load.
            if (String.IsNullOrEmpty(YouTubeMovieID))
            {
                YouTubeMovieID = dtVideoData.Rows[0]["VideoID"].ToString();
                lblDescription.Text = dtVideoData.Rows[0]["Description"].ToString();
            }
    
        }
    
        private void CreateVideoFeed()
        {
            YouTubeRequestSettings settings = new YouTubeRequestSettings("MotoGP Channel", YouTubeClientID, YouTubeDeveloperKey);
            YouTubeRequest request = new YouTubeRequest(settings);
    
            //Link to the feed we wish to read from
            string feedUrl = String.Format("http://gdata.youtube.com/feeds/api/users/{0}/uploads?orderby=published", YouTubeChampionshipChannel); ;
                    
            dtVideoData.Columns.Add("Title");
            dtVideoData.Columns.Add("Description");
            dtVideoData.Columns.Add("DateUploaded");
            dtVideoData.Columns.Add("Ratings");
            dtVideoData.Columns.Add("NoOfComments");
            dtVideoData.Columns.Add("VideoID");
            dtVideoData.Columns.Add("Duration");
    
            DataRow drVideoData;
    
            Feed<Video> videoFeed = request.Get<Video>(new Uri(feedUrl));
    
            //Iterate through each video entry and store details in DataTable
            foreach (Video videoEntry in videoFeed.Entries)
            {
                drVideoData = dtVideoData.NewRow();
    
                drVideoData["Title"] = videoEntry.Title;
                drVideoData["Description"] = videoEntry.Description;
                drVideoData["DateUploaded"] = videoEntry.Updated.ToShortDateString();
                drVideoData["Ratings"] = videoEntry.YouTubeEntry.Rating.Average.ToString();
                drVideoData["NoOfComments"] = videoEntry.CommmentCount.ToString();
                drVideoData["VideoID"] = videoEntry.YouTubeEntry.VideoId;
                drVideoData["Duration"] = videoEntry.YouTubeEntry.Duration.Seconds.ToString();
    
                dtVideoData.Rows.Add(drVideoData);            
            }
    
            repVideoList.DataSource = dtVideoData;
            repVideoList.DataBind();
        }
    
        protected void repVideoList_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                DataRowView drVideo = (DataRowView)e.Item.DataItem;
    
                LinkButton showVideo = (LinkButton)e.Item.FindControl("btnShowVideo");
                Literal title = (Literal)e.Item.FindControl("Title");
                Literal description = (Literal)e.Item.FindControl("Description");
                Literal ratings = (Literal)e.Item.FindControl("Ratings");
                Literal noOfComments = (Literal)e.Item.FindControl("NoOfComments");
                Literal duration = (Literal)e.Item.FindControl("Duration");
    
                showVideo.CommandArgument = drVideo["VideoID"].ToString();
                title.Text = drVideo["Title"].ToString();
                description.Text = drVideo["Description"].ToString();
                ratings.Text = drVideo["Ratings"].ToString();
                noOfComments.Text = drVideo["NoOfComments"].ToString();
                duration.Text = drVideo["Duration"].ToString();
    
            }
        }
        protected void repVideoList_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            // Pass the YouTube movie ID to flash
            YouTubeMovieID = e.CommandArgument.ToString();
    
            if (YouTubeMovieID == e.CommandArgument.ToString())
            {
                lblDescription.Text = ((Literal)e.Item.FindControl("Description")).Text;
            }
    
        }
    }
    

    ASPX Page

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div style="margin: 10px;">
            <div style="float: left; width: 300px; height: 400px; overflow: scroll;">
                <asp:Repeater ID="repVideoList" runat="server" OnItemDataBound="repVideoList_ItemDataBound"
                    OnItemCommand="repVideoList_ItemCommand">
                    <HeaderTemplate>
                        <table>
                    </HeaderTemplate>
                    <ItemTemplate>
                        <tr>
                            <td>
                                <asp:LinkButton ID="btnShowVideo" runat="server">Show Video</asp:LinkButton>
                                <br>
                                <strong>
                                    <asp:Literal ID="Title" runat="server"></asp:Literal></strong>
                                <br />
                                <asp:Literal ID="Description" runat="server"></asp:Literal>
                                <br />
                                Rating: <asp:Literal ID="Ratings" runat="server"></asp:Literal>
                                <br />
                                Comments: <asp:Literal ID="NoOfComments" runat="server"></asp:Literal>
                                <br />
                                Duration: <asp:Literal ID="Duration" runat="server"></asp:Literal>
                                <br />
                                <br />
                            </td>
                        </tr>
                    </ItemTemplate>
                    <FooterTemplate>
                        </table>
                    </FooterTemplate>
                </asp:Repeater>
            </div>
            <div style="float: left; margin-left: 15px;width:600px;2">
                <object width="480" height="385" style="float: left; clear: both; margin-bottom: 10px;">
                    <param name="movie" value="http://www.youtube.com/v/<%=YouTubeMovieID %>&hl=en&fs=1&rel=0">
                    </param>
                    <param name="allowFullScreen" value="true"></param>
                    <param name="allowscriptaccess" value="always"></param>
                    <embed src="http://www.youtube.com/v/<%=YouTubeMovieID %>&hl=en&fs=1&rel=0" type="application/x-shockwave-flash"
                        allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed>
                </object>
                <div style="float: left;">
                    <asp:Label ID="lblDescription" runat="server"></asp:Label>
                </div>
            </div>
        </div>
        </form>
    </body>
    </html>
    

    This is just the beginning on what the YouTube API has to offer. For more information, visit the YouTube API website (http://code.google.com/apis/youtube/2.0/developers_guide_dotnet.html).

    * Post Updated 18/06/2009 – You can output YouTube video’s via RSS feed *