Monday, 24 September 2012

Programmatically uploading videos to YouTube using C#

Recently I spent some time investigating the Google Data .NET Client library. Specifically, I was interested in the YouTube Data API. What I wanted to do was programmatically upload a video file to my YouTube account. I ran into a couple of (minor) speed bumps along the way, and noticed there were a few things that weren't as clear as they should have been. Hopefully I can clarify the problems I encountered, in case future developers run into the same trip ups. Let's get started.

For the context of this post, I should explain my development environment. I am using the following:

  • Windows 7 Professional (32-bit)

  • Visual Studio 2008 Professional SP1

  • .NET 3.5 SP1

  • ASP.NET MVC 1.0

OK, so we're going to set up a very basic ASP.NET MVC web site that will basically do two things: 

  • Provide a link to use for authenticating a Google Account

  • Provide a form to direct upload a video (including metadata)

First things first: download the most up to date version of the Google Data .NET Client library and follow the instructions for installing and setting it up.

Next, ensure you have a YouTube developer API key attached to your YouTube account. If you have not done this yet, go here and associate a Developer ID with your account. Take note of this ID (it's pretty long).

Now, let's set up a new ASP.NET MVC project. We're going to use the Visual Studio defaults here, and just name our project "YouTubeUploader". 



Next, we need to add some references to the Google APIs. When you install the Google Data API, there should be a solution at All Programs -> Google Data API SDK -> Google Data API SDK.sln that the setup guide tells you to open and build. Once you have done this, you can select these binaries as a reference in your current project, which is what we do here.



Next, we're going to create a ViewModel to encapsulate all the inputs required to pass to our video uploader. This is going to be a very basic ViewModel, with nothing more than properties for retrieving inputs for our video. Here's what the code looks like:


  1. namespace YouTubeUploader.Models  
  2. {  
  3.     public class UploadViewModel  
  4.     {  
  5.         public string Title { getset; }  
  6.         public string Keywords { getset; }  
  7.         public string Description { getset; }  
  8.         public bool Private { getset; }  
  9.         public string VideoTags { getset; }  
  10.         public double Latitude { getset; }  
  11.         public double Longitude { getset; }  
  12.         public string Path { getset; }  
  13.         public string Type { getset; }  
  14.     }  
  15. }  

Like I said, very basic ViewModel here.

Next, we need to add a controller method to handle our Login logic. For simplicity sake, we're going to use the HomeController for all of our methods here. In your production situation, however, this logic might be split apart into different modules. We're just going for the basic "Hello, World" functionality here. In order to successfully make YouTube API calls (or any Google Data API, for that matter) you must retrieve an authenticated session token from the Google servers. This can be accomplished a number of different ways. Since we're trying to make a web site here, we're going to go with the AuthSub method of Google authentication. Here, we're going to provide a link to our user where they can go and authenticate themselves with the Google servers, send back a session token, and then finally re-direct the user back to a page of our choosing. This token is returned as part of the request query string, which we can handle in a number of different ways. For our purposes, we are going to use a string parameter on one of our controller methods to take the parameter and use it to create an authenticated session token in memory. The method will look like this: 
(NOTE: throughout the post, I reference "http://localhost:50555/" as my development server. I am just running my site through Visual Studio 2008 and am taking the default server address provided. This may vary in your environment, so please replace this address for what your environment requires.)
  1. public ActionResult Login()  
  2.        {  
  3.            Session["authSubUrl"] = AuthSubUtil.getRequestUrl("http://localhost:50555/Home/Upload""http://gdata.youtube.com"falsetrue);  
  4.   
  5.            return View();  
  6.        }  

What we're doing here is using a Google utility (AuthSubUtil.getRequestUrl) to generate the text for our link to provide to our users. getRequestUrl takes the following parameters:

  • continueUrl: Where the user will be redirected after authenticating. For our example, I used my local development server (http://localhost:50555/Home/Upload) since I want to pass my authenticated session token into my Upload GET method...more on that next.

  • scope: for YouTube API calls we use http://gdata.youtube.com

  • secure: If you have registered your app with Google with the appropriate security credentials, you can set this to true to ensure that your API requests do not show the "Warning: Access Consent" verbiage after authenticating. Also, some API calls are not allowed unless your app is registered. For our testing, we send in false.

  • session: Whether the authenticated token should persist over multiple API calls or just be a "one-time-only" shot. This becomes very clear when we actually create our YouTubeRequest object.

Next we add a view for our Login page. It's going to be a very generic view, with only one link on the page. Here is the whole view:


  1. <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>  
  2.     <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">  
  3.      Login  
  4.     </asp:Content>  
  5.     <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">  
  6.         <h2>Login</h2>  
  7.         <a href="<%= Session["authSubUrl"] %>">Click here to login</a>  
  8. </asp:Content>  

Notice how we are retrieving the URL text from Session["authSubUrl"], which we set in our Login() method. You could just as easily encapsulate this value into a ViewModel, however, I felt for the type of exercise we're performing here, this was sufficient.

Let's compile our project now and run our website. What you see when you navigate to http://localhost:/Home/Login is similar to the following:



The link brings us to a very familiar page to anyone with a Google account:



Once the user has entered their credentials, the following screen shows up:



This is the warning I mentioned previously about a secure application. If you secure your site with Google, the verbiage here (according to the documentation) is omitted. I have not yet secured a site with Google yet, so I have not experienced this difference.

After clicking on "Allow Access", we're presented with the following screen:



D'oh! We don't have an Upload view or controller method yet to handle this redirect! This is what we will create next. Take a look at the URL that Google navigated to post-login.http://localhost:50555/Home/Upload?token=CPvdxbuhGRDovLiXBw That looks awfully similar to what we specified in our Login() method, doesn't it? And you can see the authenticated token in the QueryString at the end of our URL. 

Next we add a controller method to handle GET requests to our Upload page. This is where we are going to handle binding our session token into a YouTubeRequestSettings object, and we'll use that to build a YouTubeRequest object, which is how we'll interact with the YouTube Data API. The method looks like this:
  1. public ActionResult Upload(string token)  
  2. {  
  3.     Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null);  
  4.   
  5.     return View();  
  6. }  

Ok, what we're doing here is handling the QueryString token we get back from Google as a part of the GET request by making sure our method has a string parameter (which we call token). The method then uses a method on AuthSubUtil called exchangeForSessionToken which takes a string and an AsymmetricAlgorithm and returns a token good for an entire user session. This way we only have to authenticate the user once per session and they can make as many API calls as the system allows. Since we are not using a secured certificate for authentication we are leaving this as a null parameter. However, if you choose to use this functionality in a production environment I highly suggest taking a look at the documentation on registering your app with Google to take advantage of the heightened security. As this is a simple exercise, we are omitting this.

Next we add a strongly typed view (Create) for our Upload logic (UploadViewModel). We are going to choose "Create" template from the dropdown, and our view comes out like so:


  1. <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<YouTubeUploader.Models.UploadViewModel>" %>  
  2.     <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">  
  3.      Upload  
  4.     </asp:Content>  
  5.     <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">  
  6.         <h2>Upload</h2>  
  7.         <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>  
  8.         <% using (Html.BeginForm()) {%>  
  9.             <fieldset>  
  10.                 <legend>Fields</legend>  
  11.                 <p>  
  12.                     <label for="Title">Title:</label>  
  13.                     <%= Html.TextBox("Title") %>  
  14.                     <%= Html.ValidationMessage("Title", "*") %>  
  15.                 </p>  
  16.                 <p>  
  17.                     <label for="Keywords">Keywords:</label>  
  18.                     <%= Html.TextBox("Keywords") %>  
  19.                     <%= Html.ValidationMessage("Keywords", "*") %>  
  20.                 </p>  
  21.                 <p>  
  22.                     <label for="Description">Description:</label>  
  23.                     <%= Html.TextBox("Description") %>  
  24.                     <%= Html.ValidationMessage("Description", "*") %>  
  25.                 </p>  
  26.                 <p>  
  27.                     <label for="Private">Private:</label>  
  28.                     <%= Html.TextBox("Private") %>  
  29.                     <%= Html.ValidationMessage("Private", "*") %>  
  30.                 </p>  
  31.                 <p>  
  32.                     <label for="VideoTags">VideoTags:</label>  
  33.                     <%= Html.TextBox("VideoTags") %>  
  34.                     <%= Html.ValidationMessage("VideoTags", "*") %>  
  35.                 </p>  
  36.                 <p>  
  37.                     <label for="Latitude">Latitude:</label>  
  38.                     <%= Html.TextBox("Latitude") %>  
  39.                     <%= Html.ValidationMessage("Latitude", "*") %>  
  40.                 </p>  
  41.                 <p>  
  42.                     <label for="Longitude">Longitude:</label>  
  43.                     <%= Html.TextBox("Longitude") %>  
  44.                     <%= Html.ValidationMessage("Longitude", "*") %>  
  45.                 </p>  
  46.                 <p>  
  47.                     <label for="Path">Path:</label>  
  48.                     <%= Html.TextBox("Path") %>  
  49.                     <%= Html.ValidationMessage("Path", "*") %>  
  50.                 </p>  
  51.                 <p>  
  52.                     <label for="Type">Type:</label>  
  53.                     <%= Html.TextBox("Type") %>  
  54.                     <%= Html.ValidationMessage("Type", "*") %>  
  55.                 </p>  
  56.                 <p>  
  57.                     <input type="submit" value="Create" />  
  58.                 </p>  
  59.             </fieldset>  
  60.         <% } %>  
  61.  <div>  
  62.   <%=Html.ActionLink("Back to List", "Index") %>  
  63.  </div>  
  64.     </asp:Content>  

This is a very limited view. What we are doing is adding a field for every property on our UpdateViewModel. This allows the user to specify what kind of video they want to upload.

Next we add a controller method to handle the POST request for our Upload page (i.e. what happens when we click "Create"). This is where the bulk of our logic will reside. Here's what the code looks like:
  1. [AcceptVerbs(HttpVerbs.Post)]  
  2. public ActionResult Upload(UploadViewModel uploadViewModel)  
  3. {  
  4.     const string developerKey = "THIS_IS_WHERE_YOUR_REALLY_LONG_DEVELOPER_API_KEY_GOES";  
  5.     const string applicationName = "THIS_IS_WHERE_YOUR_APP_NAME_GOES";              
  6.   
  7.     _settings = new YouTubeRequestSettings(applicationName, "ThisCanSeriouslyBeAnyString_It'sBeenDeprecated", developerKey, (string) Session["token"]);  
  8.     _request = new YouTubeRequest(_settings);  
  9.   
  10.     var newVideo = new Video();  
  11.   
  12.     newVideo.Title = uploadViewModel.Title;  
  13.     newVideo.Keywords = uploadViewModel.Keywords;  
  14.     newVideo.Description = uploadViewModel.Description;  
  15.     newVideo.YouTubeEntry.Private = uploadViewModel.Private;  
  16.   
  17.     newVideo.YouTubeEntry.Location = new GeoRssWhere(uploadViewModel.Latitude, uploadViewModel.Longitude);  
  18.   
  19. wVideo.Tags.Add(new MediaCategory(uploadViewModel.VideoTags, YouTubeNameTable.DeveloperTagSchema));  
  20.   
  21.     newVideo.YouTubeEntry.MediaSource = new MediaFileSource(uploadViewModel.Path, uploadViewModel.Type);  
  22.     var createdVideo = _request.Upload(newVideo);  
  23.   
  24.     return View();  
  25. }  

Ok, so it was this method where I ran into the gotcha's that prompted me to write this post in the first place. Once again, in a production environment, you will probably have the developerKey and applicationName stored in some kind of configuration file / object or a database. For our example, we're just setting some hard-coded strings inside our method. These are used to create our YouTubeRequestSettings object. As you can see, the method takes 4 parameters, and this is the method call that was a pain to debug. The 4 parameters are:

  • applicationName: The name of our application, as specified in our YouTube Account screen, to the left of our developer api key.

  • client: If you look on your YouTube account screen (as of February 24th, 2010) you'll notice thereis not a client id on your screen. In fact, there is verbiage stating that they are no long required.Use any string you want here. Anything. I used "ThisIsMyRidiculouslyLongClientIdStringThatWillWorkJustBecause" and that is fine. It can be anything. I don't know why this hasn't been deprecated yet, but hopefully in the future it does to reduce confusion.

  • developerKey: This is your developer key from your YouTube account page. It's really long, so be sure when you copy / paste it in that you grabbed everything.

  • authSubToken: This is the string version of the AuthSub session token we created in our Login() method.

Once you understand the functionality in setting up your YouTubeRequestSettings object the rest is a walk in the park. The YouTubeRequest object itself takes a YouTubeRequestSettings object as a parameter, so you just new() up one of those with the YouTubeRequestSettings object we just created. Then, we create a new Video() object and set the properties on it equal to the values in our UploadViewModel. This is an ideal situation for AutoMapper in that all we're doing is basically mapping properties from one object to another. However, for this example we are just going to set them explicity ourselves. Then we create a new MediaFileSource object as a property on our Video object. Be sure to escape '\' in your path, if you are using a local path (i.e. instead of C:\MyCode\Project you need C:\\MyCode\\Project). Also, for the Type property, you need the MIME type of the video you are uploading. For example, for Windows Media Video files, you want to use "video/x-ms-wmv" as your type.

And that's it! Let's run the web site now and see our results.

To make this more robust (and actually usable) you'll want to provide some kind of feedback mechanism to notify your user whether the upload failed or was successful. For this example I chose to just prove how to upload the files. 

I hope this eases someone's pain and eliminates the 45 minutes - 1 hour I lost trying to figure out why my API calls weren't being correctly authenticated. Take some time and experiment with the rest of the APIs, which allows you to do pretty much anything you can do on the web site.

Saturday, 15 September 2012

The History and Progress of SAP

The History and Progress of SAP You would have heard this word quite a number of times “SAP”. This word (or an abbreviation) which brightens many an eye. For a IT professional it symbolizes a dream career, for a customer a sigh of relief, for SAP partner a sigh of joy. “SAP” rather a small word but it has become a part or cause of life for many in a short span of time, what is it? What it does? Is what we are going to see in this article
The birth and progress of SAP
SAP is a company which was founded in Germany in 1972 by five people who were working in IBM before that, it is a dream of these people to develop a common package for many a business processes made SAP possible
SAP stands for Systeme, Andwendungen, Produkte in der Datenverarbeitung (these are German words which - translated to English - means Systems, Applications, Products in Data Processing)
The company is incorporated in Germany; with the name SAP AG (it is the parent company). It is located in Walldorf, Germany which is close to the beautiful town of Heidelberg. SAP has subsidiaries in over 50 countries around the world from Argentina to Venezuela. SAP Labs India is SAP's second largest Research & Development and Global Services & Support center in the world. Founded in November 1998, SAP Labs India is one of the four global development hubs (Germany, US and Israel being others) of SAP that contribute to all areas of the SAP product value chain- Research & Breakthrough Innovation, Product Development, Global Services & Support and Customer Solutions & Operations. It is located in Bangalore, India
The original five founders have been so successful that they have multiplied many times over such that SAP AG is now the third largest software maker in the world, with over 17,500 customers (including more than half of the world's 500 top companies). SAP employs over 27,000 people worldwide today, and had revenues of $7.34 billion and Net Income of $581 million in FY01. SAP is listed in Germany (where it is one of the 30 stocks which make up the DAX) and on the NYSE (ticker: SAP).
There are now 44,500 installations of SAP, in 120 countries, with more then 10 million users!
Why SAP is so successful?
Let us look in to the success story of SAP and find out what made it so successful. Back in 1979 SAP made inroads in German market and released SAP R/2 (which runs on mainframes). SAP R/2 was the first integrated, enterprise wide package it was an immediate success.
SAP stayed within the German borders until it had penetrated practically every large German company. SAP expanded into the remainder of Europe during the 80's. Towards the end of the 80's, client-server architecture became popular and SAP responded with the release of SAP R/3 (in 1992). This turned out to be a killer application for SAP, especially in the North American region into which SAP expanded in 1988.
The success of SAP R/3 in North America has been nothing short of stunning. Within a 5 year period, the North American market went from virtually zero to 44% of total SAP worldwide sales. SAP America alone employs more than 3,000 people and has added the names of many of the Fortune 500 to its customer list (8 of the top 10 semiconductor companies, 7 of the top 10 pharmaceutical companies etc). SAP today is available in 46 country-specific versions, incorporating 28 languages including Kanji and other double-byte character languages. SAP also comes in 21 specified industry versions
What is done with SAP?
SAP R/3 is delivered to a customer with selected standard process turned on, and many other optional processes and features turned off. At the heart of SAP R/3 are about 10,000 tables which control the way the processes are executed. Configuration is the process of adjusting the settings of these tables to get SAP to run the way you want it to. Think of a radio with 10,000 dials to tune and you’ll get the picture. Functionality included is truly enterprise wide including: Financial Accounting (e.g. general ledger, accounts receivable etc), Management Accounting (e.g. cost centers, profitability analysis etc), Sales, Distribution, Manufacturing, Production Planning, Purchasing, Human Resources, Payroll etc All of these modules are tightly integrated which – as you will find out – is a huge blessing ... but brings with it special challenges.
How SAP is still a leader?
SAP are maintaining and increasing their dominance over their competitors through a combination of
- embracing the internet with mySAP.com (a confusing name we believe) to head off i2 etc - extending their solutions with CRM to head off Siebel - adding functionality to their industry solutions

Thursday, 13 September 2012

Usage Of Unions with typedef

Can you predict the output of this program ?
main()
{
        typedef union {
           int     a;
           char    b[10];
           float   c;
        } Union
        Union   x, y = { 100 }; // here y = 100 bcoz its property of union
        x.a = 50;s
trcpy (x.b, "hello");
        x.c = 21.50;
        printf ("Union x : %d %s %f\n", x.a, x.b, x.c);
        printf ("Union Y : %d %s %f\n", y.a, y.b, y.c);
}


Solution:

This is the  problem  about  Unions.  Unions are  similar to
structures  but it  differs  in  some  ways.  Unions  can be
assigned  only  with one  field at any time.  In this  case,
unions x and y can be  assigned  with any of the one field a
or b or c at one time.  During  initialisation  of unions it
takes  the value  (whatever  assigned  ) only for the  first
field.  So, The statement y = {100}  intialises  the union y
with field a = 100.
In this  example,  all fields of union x are  assigned  with
some  values.  But at any time only one of the  union  field
can  be  assigned.  So,  for  the  union  x the  field  c is
assigned as 21.50.
Thus, The output will be 
        Union x : 22 22 21.50
        Union Y : 100 22 22
        ( 22 refers unpredictable results ) 

Reference :


http://www.c-puzzles.thiyagaraaj.com/level-two.html


Wednesday, 12 September 2012

How To Check If An Element Exists In JQuery


<html>
<head>
 
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
 
</head>
 
<body>
 
<h1>jQuery check if an element exists</h1>
 
<script type="text/javascript">
 
  $(document).ready(function(){
 
    $("#buttonDiv1").click(function () {
 
 if($('#div1').length){
  alert("Div1 exists");
 }else{
  alert("Div1 does not exists");
 }
 
    });
 
    $("#buttonDiv2").click(function () {
 
 if($('#div2').length){
  alert("Div2 exists");
 }else{
  alert("Div2 does not exists");
 }
 
    });
 
  });
</script>
</head><body>
 
<div id="div1">
 <b>This is DIV element which has an ide of "div1"</b>
</div>
 
<br/>
<br/>
<br/>
 
<input type='button' value='div1 exists?' id='buttonDiv1'>
<input type='button' value='div2 exists?' id='buttonDiv2'>
 
</body>
</html>

How To Stop A Page From Exit Or Unload With JQuery


<html>
<head>
<title>Refresh a page in jQuery</title>
 
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
 
</head>
 
<body>
 
<h1>Stop a page from exit with jQuery</h1>
 
<button id="reload">Refresh a Page in jQuery</button>
 
<script type="text/javascript">
 
 $('#reload').click(function() {
 
   location.reload();
 
 });
 
 $(window).bind('beforeunload', function(){
  return '>>>>>Before You Go<<<<<<<< \n Your custom message go here';
 });
 
</script>
 
</body>
</html>

Page Loading Effects With JQuery


<html>
<head>
<title>JQuery Page Loading Effect</title>
 
<script type="text/javascript" src="jquery.js"></script>
 
</head>
 
<script type="text/javascript">
 
$(document).ready(function(){
 
 $('#page_effect').fadeIn(2000);
 
});
 
</script>
<body>
 
<div id="page_effect" style="display:none;">
 
<h1>JQuery Page Loading Effect</h1>
 
    This is page loading effect with JQuery 1<BR>
    This is page loading effect with JQuery 2<BR>
    This is page loading effect with JQuery 3<BR>
    This is page loading effect with JQuery 4<BR>
    This is page loading effect with JQuery 5<BR>
    This is page loading effect with JQuery 6<BR>
    This is page loading effect with JQuery 7<BR>
    This is page loading effect with JQuery 8<BR>
    This is page loading effect with JQuery 9<BR>
    This is page loading effect with JQuery 10<BR>
    This is page loading effect with JQuery 11<BR>
    This is page loading effect with JQuery 12<BR>
    This is page loading effect with JQuery 13<BR>
    This is page loading effect with JQuery 14<BR>
</div>
 
</body>
</html>

What should you required to learn machine learning

  To learn machine learning, you will need to acquire a combination of technical skills and domain knowledge. Here are some of the things yo...