Windows Phone - Programming : How to parse YouTube API response

How to parse YouTube API response

This article demonstrates how to use YouTube standard and search APIs to play videos on Windows Phone.

Introduction

There is nothing hard about playing streaming video on Windows Phone, as the default player takes care of it seamlessly - for more information see the article Video Playback with MediaElement in Windows Phone.
When working with YouTube content the main difficulty is parsing the video URL response from the YouTube API. This is problematic because YouTube provides a text based percent encoding which is not always in the same format for a particular video id.
This article shows how to decode the video URL from the percent encoding response (the basic string parsing technique used can be found in VideoUrl.cs).

Implementation

Create a standard Windows Phone Project

Let’s create a standard Windows Phone Application Project
  • Launch Visual Studio
  • Click on File
  • Click on New Project
  • Select Windows Phone Panorama App (Visual C# Template)
  • Add Name and Location of the project
  • Click OK to create the project.

Adding UI controls on application page

We have created two sections in the panorama view, one where we display TopRated, MostPopular, MostShared, RecentlyFeatured, TopFavorites, MostViewed and the other section where user can search for a particular video and display the list. Let’s open the MainPage.xaml file and paste the below code to create the UI.
<Grid x:Name="LayoutRoot" Background="Transparent">
        <!--Panorama control-->
        <controls:Panorama Title="YouTube Demo">
            <controls:Panorama.Background >
                <ImageBrush ImageSource="PanoramaBackground.png" Opacity="0.2"/>
            </controls:Panorama.Background>
            <!--Panorama item one-->
            <controls:PanoramaItem Header="Videos" Orientation="Horizontal" >
                <Grid x:Name="gridFirstItems"    >
                    <StackPanel x:Name="mainStackPanel" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
                        <StackPanel Name="bigImage"    Orientation="Horizontal"  >
                            <StackPanel Orientation="Vertical">
                            <Rectangle Height="358" Width="358" Margin="12,0,12,0" Tap="Rectangle_Tap"  >
                                <Rectangle.Fill>
                                    <SolidColorBrush Color="{StaticResource PhoneAccentColor}" />
                                </Rectangle.Fill>
                             </Rectangle>
                                <Image Name="img_TopRated" Tap="Rectangle_Tap" Height="358" Width="358" Stretch="UniformToFill" Margin="12,-358,12,0"></Image>
                                <Rectangle Height="100" Width="358" Margin="12,-100,12,0" Opacity="0.7" >
                                    <Rectangle.Fill  >
                                        <SolidColorBrush Color="{StaticResource PhoneBackgroundColor}"  />
                                    </Rectangle.Fill>
                                </Rectangle>
                                <TextBlock Text="Top rated" Style="{StaticResource PhoneTextTitle1Style}" Foreground="{StaticResource PhoneForegroundBrush}"  Margin="18,-100,12,0" />
                            </StackPanel>                        
                        </StackPanel>
                        <StackPanel Name="smallImages" Margin="0,0,0,0" Orientation="Vertical">
                            <StackPanel Name="firstRow" Orientation="Horizontal">
                                <StackPanel Orientation="Vertical">
                                <Rectangle Height="173" Width="173" Margin="0,0,12,0" Tap="Rectangle_Tap_1">
                                    <Rectangle.Fill>
                                        <SolidColorBrush Color="{StaticResource PhoneAccentColor}" />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <Image Name="img_MostPopular" Tap="Rectangle_Tap_1" Height="173" Width="173" Stretch="UniformToFill" Margin="0,-173,12,0"></Image>
                                <Rectangle Height="50" Width="173" Margin="0,-50,12,0" Opacity="0.7" >
                                    <Rectangle.Fill>
                                            <SolidColorBrush Color="{StaticResource PhoneBackgroundColor}" />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <TextBlock Text="Most popular" Style="{StaticResource PhoneTextTitle3Style}" Foreground="{StaticResource PhoneForegroundBrush}"  Margin="6,-50,12,0" />
                                </StackPanel>
                                <StackPanel Orientation="Vertical">
                                <Rectangle Height="173" Width="173" Margin="0,0,12,0" Tap="Rectangle_Tap_2">
                                    <Rectangle.Fill>
                                        <SolidColorBrush Color="{StaticResource PhoneAccentColor}" />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <Image Name="img_MostShared" Tap="Rectangle_Tap_2" Height="173" Width="173" Stretch="UniformToFill" Margin="0,-173,12,0"></Image>
                                <Rectangle Height="50" Width="173" Margin="0,-50,12,0" Opacity="0.7" >
                                    <Rectangle.Fill>
                                            <SolidColorBrush Color="{StaticResource PhoneBackgroundColor}"  />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <TextBlock Text="Most shared" Style="{StaticResource PhoneTextTitle3Style}" Foreground="{StaticResource PhoneForegroundBrush}"  Margin="6,-50,12,0" />
                                </StackPanel>
                             <StackPanel Orientation="Vertical">
                            <Rectangle Height="173" Width="173" Margin="0,0,12,0" Tap="Rectangle_Tap_3">
                                    <Rectangle.Fill>
                                        <SolidColorBrush Color="{StaticResource PhoneAccentColor}" />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <Image Name="img_TopFavorites" Tap="Rectangle_Tap_3" Height="173" Width="173" Stretch="UniformToFill" Margin="0,-173,12,0"></Image>
                                    <Rectangle Height="50" Width="173" Margin="0,-50,12,0" Opacity="0.7" >
                                <Rectangle.Fill>
                                            <SolidColorBrush Color="{StaticResource PhoneBackgroundColor}" />
                                </Rectangle.Fill>
                            </Rectangle>
                                    <TextBlock Text="Top favorites" Style="{StaticResource PhoneTextTitle3Style}" Foreground="{StaticResource PhoneForegroundBrush}"  Margin="6,-50,12,0" />
                                </StackPanel>
                            </StackPanel>
                        <StackPanel Name="secondRow" Orientation="Horizontal" Margin="0,12,12,0">
                                <StackPanel Orientation="Vertical">
                                    <Rectangle Height="173" Width="358" Margin="0,0,12,0" Tap="Rectangle_Tap_4">
                                    <Rectangle.Fill>
                                        <SolidColorBrush Color="{StaticResource PhoneAccentColor}" />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <Image Name="img_RecentlyFeatured" Tap="Rectangle_Tap_4" Height="173" Width="358" Stretch="UniformToFill" Margin="0,-173,12,0"></Image>
                                <Rectangle Height="50" Width="358" Margin="0,-50,12,0" Opacity="0.7" >
                                    <Rectangle.Fill>
                                            <SolidColorBrush Color="{StaticResource PhoneBackgroundColor}" />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <TextBlock Text="Recently featured" Style="{StaticResource PhoneTextTitle3Style}" Foreground="{StaticResource PhoneForegroundBrush}"  Margin="6,-50,12,0" />
                                </StackPanel>
                                <StackPanel Orientation="Vertical">
                                    <Rectangle Height="173" Width="173" Margin="0,0,12,0" Tap="Rectangle_Tap_5">
                                    <Rectangle.Fill>
                                        <SolidColorBrush Color="{StaticResource PhoneAccentColor}" />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <Image Name="img_MostViewed" Tap="Rectangle_Tap_5" Height="173" Width="173" Stretch="UniformToFill" Margin="0,-173,12,0"></Image>
                                <Rectangle Height="50" Width="173" Margin="0,-50,12,0" Opacity="0.7" >
                                    <Rectangle.Fill>
                                            <SolidColorBrush Color="{StaticResource PhoneBackgroundColor}" />
                                    </Rectangle.Fill>
                                </Rectangle>
                                    <TextBlock Text="Most viewed" Style="{StaticResource PhoneTextTitle3Style}" Foreground="{StaticResource PhoneForegroundBrush}"  Margin="6,-50,12,0" />
                                </StackPanel>
                        </StackPanel>
                        </StackPanel>
                        </StackPanel> <!-- main stack panel-->
                </Grid>
            </controls:PanoramaItem>
           <!--Panorama item two-->
            <!--Use 'Orientation="Horizontal"' to enable a panel that lays out horizontally-->
            <controls:PanoramaItem Header="Search Video">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto"/>
                        <RowDefinition Height="auto" />
                    </Grid.RowDefinitions>
                    <StackPanel Orientation="Horizontal" Width="450" Grid.Row="0">
                        <TextBox Name="txt_video" TextWrapping="NoWrap" Height="72" Width="300"></TextBox>
                        <Button Content="Search" Click="Button_Click"  ></Button>
                    </StackPanel>
                    <ListBox x:Name="ListBoxSearchVideo" Height="421" Grid.Row="1" Margin="12,0,12,0" SelectionChanged="ListBoxSearchVideo_SelectionChanged"  >
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Name="stackPanelSongs" Orientation="Horizontal" Margin="0,12,0,17" >
                                    <Image Source="{Binding Image}" Stretch="UniformToFill" Height="100" Width="100"  VerticalAlignment="Top" Margin="0,0,0,0"/>
                                    <StackPanel Width="345" Height="90" Margin="0,0,0,0" >
                                        <TextBlock Name="SongTitle" Text="{Binding Title}"  TextWrapping="NoWrap" Margin="12,0,0,0"    FontFamily="Segoe WP Semibold" FontSize="28" Foreground="#efd584" />
                                        <TextBlock Text="{Binding Description}" TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextSubtleStyle}" Foreground="Peru" />
                                    </StackPanel>
                                </StackPanel>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </Grid>
            </controls:PanoramaItem>
        </controls:Panorama>
    </Grid>

Adding code behind

  • Initialize the events in the MainPage.xaml.cs
private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            IYouTubeEvents ITube = new YouTubeData();
            ITube.OnMostPopularLoaded += new MostPopular(ITube_OnMostPopularLoaded);
            ITube.OnMostSharedLoaded += new MostShared(ITube_OnMostSharedLoaded);
            ITube.OnMostViewedLoaded += new MostViewed(ITube_OnMostViewedLoaded);
            ITube.OnRecentlyFeaturedLoaded += new RecentlyFeatured(ITube_OnRecentlyFeaturedLoaded);
            ITube.OnTopFavoritesLoaded += new TopFavorites(ITube_OnTopFavoritesLoaded);
            ITube.OnTopRatedLoaded +=new TopRated(ITube_OnTopRatedLoaded);
            ITube.ConnectToYouTube();
        }
The ConnectToYouTube() method parses the YouTube video listing API and calls the respective event handler to display the video list on to the UI. Till here is very straight forward as these are REST APIs and returns response in XML format. To understand the API used in this example please see YouTubeData.cs file.
  • Once the user clicks on a particular video item we take the video id and call the GetVideoUrl() method which then puts a API request and gets percent encoding data as response.
  public void GetVideoUrl(string avideoId)
        {
              string VideoRequest = "http://www.youtube.com/get_video_info?&video_id=" + avideoId + "&el=detailpage&ps=default&eurl=&gl=US&hl=en";
           // string VideoRequest = "http://www.youtube.com/get_video_info?video_id=" + avideoId;
            WebClient xmlClient = new WebClient();
            xmlClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(DownloadStringCompleted_GetVideoUrl);
            xmlClient.DownloadStringAsync(new Uri(VideoRequest, UriKind.RelativeOrAbsolute));
       }
We use HttpUtility class to decode the response and brings to a regular text base format. We search for the string &url_encoded_fmt_stream_map= in the response and take out the data from its start to end. This response has a lot of information about the particular video, including all its file type and formats.
We are interested on Baseline MP4 format which has a tag itag=18. Search for the tag itag=18 and get the respective parameters. See Wikipedia to find out all formats supported by YouTube and their tags. You may come across to a situation where you find two itag=18 in the response and s or sig in place of signature parameter. All you need to do is to handle these conditions to get the required parameters. In this example we have checked these scenarios in VideoUrl.cs file and called OnVideoUrlLoadedevent with the final video URL which then play the video on default player in MainPage.xaml.cs file.
void IVideo_OnVideoUrlLoaded(object sender, VideoUrlArgs e)
        {
            string str = e.StrVideoUrl;          
            MediaPlayerLauncher media = new MediaPlayerLauncher();
            media.Media = new Uri(str, UriKind.RelativeOrAbsolute);
            media.Show();
        }
The same concept is applied to YouTube video search also, where you can search a video from YouTube and play it.
To keep the article short I haven’t put the complete source code here. Please download the source code for better understanding.

Summary

Using this example you can call other YouTube APIs and get the video played. I couldn't find any library to parse percent encoding data, so used a very basic logic to parse it as a string component. If you find any better way of parsing percent encoding data feel free to share it with us.

Source Code

Nhận xét

Bài đăng phổ biến