Thursday, April 28, 2011

Communicating with data services of third party , YouTube sample - II


This is the second part of the YouTube Sample, which shows you how to connect to YouTube's data services. Following is the code of the others script events:

database5_3_ready event:

// create textInput to get the search string from the user
var cw=page.findObject2("/database5_3");
var t=cw.content.application.new_textInput();
t.y=40;t.x=33;t.width=277;
// next line: when user press enter will trigger searchString_textInputEnter event
t.addEvents('enter','|','searchString')
page.content.addChild(t);
global.t=t; // saves reference to the textInput for use it in other events



// CREATE AN IMAGE AND LOAD THE CHROMELESS PLAYER FROM YOUTUBE
var im=cw.content.application.new_image();
im.y=160;im.x=33;
im.width=399;im.height=377;
im.id="player";
im.addEvents("loadComplete",'|','videoPlayer');
im.source="http://www.youtube.com/apiplayer?version=3";
page.content.addChild(im);
global.vidPlayer=im; // saves reference to the player for use it in other events

// create a vertical box which will be the video list container
create_vBox();
// create a vertical box which will be the comments list container
create_vBoxComments();

setButtonMode(); // set button mode for some componentes


videoPlayer_imageLoadComplete event:


if (me.id="player")
{
// set a listener to 'watch' when the chromeless player contained
// inside this component is ready to interaction
me.content.addEventListener("onReady",page.g_scripts.listener);
}



listener event:

if (event.currentTarget==global.vidPlayer.content && event.type=='onReady')
{
/*
the chromeless video player triggered the onReadyEvent,
signaling is ready to be used
*/
var w=500;
var h=400; //w*3/4;
event.currentTarget.setSize(w, h);
}

searchString_textInputEnter event:

/*
here we send the search request to youtube
*/
searchVideos();

database5_1_onClick event:

/*
here we send the search request to youtube
*/
searchVideos();


serverResponse event:


// prepare some variables to store the video data
var videos=new ArrayCollection();
var video=null;

// get some namespaces from the xml data

var os = result.result.namespace("openSearch");//::totalResults;
global.totalResults=result.result.os::totalResults;


var ns= result.result.namespace("");
var gd = result.result.namespace("gd");
var media = result.result.namespace("media");
var yt = result.result.namespace("yt");

var vList=null;
vList = result.result.ns::entry;


for each(var vElement in vList)
{

video=new Object();
if (video!=null)
{
video.title = vElement.ns::title;
video.published = vElement.ns::published;
video.rating = Number(vElement.gd::rating.@average);
video.description = vElement.media::group.media::description;
video.keywords = vElement.media::group.media::keywords;
video.category = vElement.media::group.media::category;
video.thumbnail = vElement.media::group.media::thumbnail[0].@url;
video.duration = Number(vElement.media::group.yt::duration.@seconds);
//video.url = vElement.media::group.media::content.(@type == "application/x-shockwave-flash").@url;
video.url = vElement.media::group.media::content.(String(@url).substr(0,4) == "http").@url;
video.urlComments=vElement.gd::comments.gd::feedLink.@href;
//if(video.url != null && video.url.length > 0)
{
videos.addItem(video);
}
}

} // end of for each

global.videos=videos; // save the videos in the global variable

// now we build the videoList from the video list
buildVideoList();

showOneOf();


serverError event:

Alert.show('error calling video search');


serverResponseComments event:


// prepare some variables to store the comments
var comments=new ArrayCollection();
var comment=null;

// get some namespaces from the xml data

var os = result.result.namespace("openSearch");
global.totalResultsComments=result.result.os::totalResults;

var ns= result.result.namespace("");


var vList=null;
vList = result.result.ns::entry;


for each(var vElement in vList)
{

comment=new Object();
if (comment!=null)
{
comment.title = vElement.ns::title;
comment.published = vElement.ns::published;
comment.updated = vElement.ns::updated;
comment.content = vElement.ns::content;
comment.authorName = vElement.ns::author.ns::name;

{
comments.addItem(comment);
}
}

} // end of for each

global.comments=comments; // save the comments in the global variable

// now we build the commentsList from the comments list
buildCommentsList();

showOneOfComments();


serverErrorComments event:

Alert.show('error calling comments for video');


database5_5_onClick event:

// user click the play video button
if (global.vidPlayer==null)
{
// cromeless video player not instantiated
return;
}
global.vidPlayer.content.playVideo();


database5_6_onClick event:

// user click the pause video button
if (global.vidPlayer==null)
{
// cromeless video player not instatiated
return;
}
global.vidPlayer.content.pauseVideo();


database5_8_onClick event:

// user click the rewind video button
if (global.vidPlayer==null)
{
// cromeless video player not instatiated
return;
}
global.vidPlayer.content.seekTo(0, true);


database5_9_onClick event:

// back the video list to the previous page
if (global.startIndex-global.maxResults>=1)
global.startIndex=global.startIndex-global.maxResults;
else
global.startIndex=1;

searchVideos();


database5_10_onClick event:

// forward the video list to the next page
if (global.startIndex+global.maxResults<=global.totalResults)
global.startIndex=global.startIndex+global.maxResults;
else
{
global.startIndex=global.totalResults-global.maxResults;
if (global.startIndex<1) global.startIndex=1;
}

searchVideos();

database5_17_onClick event:

// back the comments list to the previous page
if (global.startIndexComments-global.maxResultsComments>=1)
global.startIndexComments=global.startIndexComments-global.maxResultsComments;
else
global.startIndexComments=1;

searchComments();


database5_18_onClick event:

// forward the video list to the next page
if (global.startIndexComments+global.maxResultsComments<=global.totalResultsComments)
global.startIndexComments=global.startIndexComments+global.maxResultsComments;
else
{
global.startIndexComments=global.totalResultsComments-global.maxResultsComments;
if (global.startIndexComments<1) global.startIndexComments=1;
}

searchComments();


videoList_canvasClick event:

if (me.id.indexOf('_')==-1) // name does not adjust to name convention of name_n
return;

var arrName=me.id.split('_'); // separate name from number of component
var nameComponent=arrName[0];
var numComponent=arrName[1];

if (nameComponent=='canvVideoList')
{
// the user click on a video of the video list, so we start to play the
// selected video in the chromeless player
if (global.vidPlayer==null)
{
// cromeless video player not instatiated
return;
}
global.vidPlayer.content.loadVideoByUrl(global.videos[numComponent].url);

// set the title and description in the text above of the chromeless player
var t=page.findObject2("/database5_2");
if (t!=null)
{
t.htmlText=""+global.videos[numComponent].title+""+"\n"+global.videos[numComponent].description;
}

// search and display the comments for this video
global.startIndexComments=1;
global.totalResultsComments=0;
global.urlComments=global.videos[numComponent].urlComments;
searchComments();
}


videoList_canvasMouseWheel event:

// highlight the item of the video list where is the mouse pointer
if (global.lastCanvas!=null)
if (global.lastCanvas!=me)
{
global.lastCanvas.setStyle("backgroundColor", 0xffffff);
}

me.setStyle("backgroundColor", 0xaaaaff);
global.lastCanvas=me;


videoList_canvasRollOut event:

// restore the blank color of the item of the video list
me.setStyle("backgroundColor", 0xffffff);


videoList_canvasRollOver event:

// highlight the item of the video list where is the mouse pointer
if (global.lastCanvas!=null)
if (global.lastCanvas!=me)
{
global.lastCanvas.setStyle("backgroundColor", 0xffffff);
}

me.setStyle("backgroundColor", 0xaaaaff);
global.lastCanvas=me;


commentsList_canvasClick event:

// do nothing (for the moment)

commentsList_canvasMouseWheel event:

// highlight the item of the comments list where is the mouse pointer
if (global.lastCanvasComments!=null)
if (global.lastCanvasComments!=me)
{
global.lastCanvasComments.setStyle("backgroundColor", 0xffffff);
}

me.setStyle("backgroundColor", 0xaaaaff);
global.lastCanvasComments=me;


commentsList_canvasRollOut event:

// restore the blank color of the item of the comments list
me.setStyle("backgroundColor", 0xffffff);


commentsList_canvasRollOver event:

// highlight the item of the comments list where is the mouse pointer
if (global.lastCanvasComments!=null)
if (global.lastCanvasComments!=me)
{
global.lastCanvasComments.setStyle("backgroundColor", 0xffffff);
}

me.setStyle("backgroundColor", 0xaaaaff);
global.lastCanvasComments=me;


That's all the events for the YouTube sample. You could enhanced the page adding many more controls to the video player, etc. Because with HB you can make that very easily.

On this post you had learn how to connect to a third party data service, how to send and get data to/from the data service using the httpService object and how to create a user interface dynamically to show the data (on this case video data). You now could use this sample like a starting point to connect to others data services like FaceBook, Flickr, etc. :)


Monday, April 18, 2011

Communicating with data services of third party , YouTube sample - I

Hummingbird allow you communicate with external data services. you can do so, using the http services objects provided by HB. On this post i will show you how to communicate with the data services offered by Youtube, but you could adapt the sample to communicate with others services like the one offered for flickr, panoramio, facebook, etc.
following are two images showing the HB page at design time, with the elements needed to do the sample:




The elements found on the page are:

1. commonWidgets: this widget will allow us create the elements 3,5 and 9. id: database5_3
2. search videos: is a text component, when the user click on it, access the youtube data services, and get a video list corresponding to the words in the element 3 (textInput). id: database5_1
3. textInput: here you enter the words corresponding to the videos you want to get from youtube.
4. text: it show you the title and description of the video you are watching currently. id: database5_2
5. video player: it is the chromeless video player provided by youtube. it allow us play streamed videos directly from the YouTube's servers.
6. play button: play the video. id: database5_5
7. stop button: stop the video you are watching. id: database5_6
8. rewind button: rewind the video. id: database5_8
9. video list: this is an vBox component generated using the cwidgets, it shows you the video list corresponding to the videos that match your search criteria. it show you the videos in a paged way, and you can use the buttons below it to move between pages. When you click on a video on this list the video begins to play.
10. back video list: allow you get the previous video list page. id: database5_9
11. forward video list: allow you get the next video list page. id: database5_10
12. text: shows you the start and end videos showed on the video list, and the total of videos. id: database5_12
13. comments list: this is an vBox component generated using the cwidgets, it shows you the comments list corresponding to the video that is being played. it show you the comments in a paged way, and you can use the buttons below it to move between pages.
14. back comments list: allow you get the previous comments list page. id: database5_17
15. forward comments list: allow you get the next comments list page. id: database5_18
16. text: shows you the start and end comments showed on the comments list, and the total of comments. id: database5_19

The next pictures show you the HB page in action (on visit mode):



One of the things you must know when you try to use data services of third party is the way you will communicate with the data services and the format of the returned data. On this case we will get data from Youtube, so you will have to understand how works the YouTube API, so you must read this:

YouTube API protocol
YouTube API player

The above links will provide you with useful info in order to understand what we will do next.

A first question you could be asking yourself is ¿ why use the YouTube's video player instead the HB video player ? Youtube don't allow you access flv videos directly, instead they provides two video players which allow us play the videos. Maybe by googling sometime you could find some hacks to access flv videos directly from YouTube, but there is not guarantee it keep working , because YouTube is constantly closing that hacks.

Following you can see the scripts of the page in the scripts editor:


and next is the code of every event script:

imports event:

import mx.controls.Alert;
import mx.collections.ArrayCollection;


// create our webService object
global.serv=page.newHttpService();
global.serv.service.url="http://gdata.youtube.com/feeds/api/videos";
global.serv.service.resultFormat="e4x";
global.serv.service.method = "GET";

// the next webservice will be used to retrieve the comments for the played video
global.servComments=page.newHttpService();
global.servComments.service.resultFormat="e4x";
global.servComments.service.method = "GET";

/*
every time a search is made we will save
the results videos in the next variable
*/
global.videos=null;
// the next variable will be our video list component container
global.vb=null;
// the next variable will show us the last canvas of the video list that was higlighted
global.lastCanvas=null;
// the next 3 variables will be used to control the movement of the video list pages
global.startIndex=1;
global.maxResults=10;
global.totalResults=0; // when searching this will be filled with the total numbers of videos



// the next 3 variables will be used to control the movement of the comments list pages
global.startIndexComments=1;
global.maxResultsComments=30;
global.totalResultsComments=0; // when searching this will be filled with the total numbers of comments for the selected video
// the next variable will save the comments for a video
global.comments=null;
// the next variable will be our comments list container
global.vbComments=null;
// the next variable will show us the last canvas of the comments list that was higlighted
global.lastCanvasComments=null;
// the next variable will save the url of the comments for the video being played
global.urlComments=null;

// needed to use the chromeless player of youtube
page.allowDomain("www.youtube.com"); // this allows HB access the chromeless YouTube video player

global.vidPlayer=null; // this will be the chromeless videoPlayer Object

functions event:


function clearCommentsList()
{
if (global.vbComments!=null)
global.vbComments.removeAllChildren();


}



function buildCommentsList()
{
/*
this function take the data of the comments and build a nice
comments list
*/

clearCommentsList();

// get a reference to the cWidget
var cw=page.findObject2("/database5_3");

// get a reference to the vertical box created
var vb=global.vbComments;
if (vb==null)
{
Alert.show("vbox for comments list not created");
return;
}


// loop over our comments list
for (var i = 0 ; i < global.comments.length ; i++)
{
// this is the i-esimal comment of the list


/* the data fields for a comment are:
comment.title
comment.published
comment.updated
comment.content
comment.authorName
*/



// create a text object to show some text of the video
var text=cw.content.application.new_text();
text.y=6;text.x=4;
text.width=vb.width-24;
//text.height=100; // component will be autosized according content
text.autoResize=true;
text.htmlText="TITLE: "+global.comments[i].title+"\nAUTHOR: "+global.comments[i].authorName+"\n"+global.comments[i].content;
text.setStyle("color", 0x000000);
text.id="text"+i;
//text.truncateToFit=true; // dont need truncateToFit
//text.addEvents("click");
text.toolTip=global.comments[i].content;
text.mouseChildren=false;



// create a canvas an locate every above object inside it
var can=cw.content.application.new_canvas();
can.setStyle("backgroundColor", 0xffffff);
can.setStyle("borderStyle", "solid");
can.setStyle("borderColor", 0x000000);
can.setStyle("borderThickness", 1);
can.autoLayout=true;
can.addChild(text);

//can.height=text.y+text.height+4; // canvas will be autoLayout
//can.width=text.x+text.width+4; // canvas will be autoLayout
can.id="canvCommentsList_"+i;
/*
next line: the events of the canvas (rollover,rollOut, etc.) will begin with commentsList prefix
*/
can.addEvents("rollOver|rollOut|click|mouseWheel",'|','commentsList');
can.hScrollPolicy("off");
can.vScrollPolicy("off");
can.buttonMode=true;

// add the canvas with its childrens to the container vBox
vb.addChild(can);

}

} // end of function buildCommentsList




function showOneOfComments()
{
// set the a message like this: 1-10 of 123
var c=page.findObject2("/database5_19");
if (c!=null)
{
c.text=global.startIndexComments+"-"+(global.startIndexComments+global.maxResultsComments-1)+" of "+global.totalResultsComments;
}
}


function searchComments()
{
// this function search for the comments of a video
if (global.urlComments==null)
return;

var startIndex=global.startIndexComments;
var maxResults=global.maxResultsComments;

global.servComments.service.url=global.urlComments;
var params=new Object();
params["max-results"]=maxResults;
params["start-index"]=startIndex;

global.servComments.call(params,"serverResponseComments","serverErrorComments");

}

function create_vBoxComments()
{
var cw=page.findObject2("/database5_3");

// creates a vBox which will be the container for the comments list
var vb=cw.content.application.new_vBox();
// set styles for vBox
vb.setStyle("borderStyle", "solid");
vb.setStyle("borderColor", 0x000000);
vb.setStyle("borderThickness", 1);
vb.setStyle("verticalGap", 0); // vertical space between childrens

vb.height=473;
vb.width=397;
vb.x=34;vb.y=544;
vb.setStyle("backgroundColor", 0xffffff);
page.content.addChild(vb);
global.vbComments=vb;

} // end of function vBoxComments



function setButtonMode()
{
// set buttonMode for search videos button
var pb=page.findObject2("/database5_1");
pb.buttonMode=true;
pb.mouseChildren=false; // this is a text so we need this too

// set buttonMode for the player buttons (play,stop,rewind)
var pb=page.findObject2("/database5_5");
pb.buttonMode=true;
var pb=page.findObject2("/database5_6");
pb.buttonMode=true;
var pb=page.findObject2("/database5_8");
pb.buttonMode=true;

// set button mode for videolist buttons (back video list,forward video list)
var pb=page.findObject2("/database5_9");
pb.buttonMode=true;
var pb=page.findObject2("/database5_10");
pb.buttonMode=true;

// set button mode for commentslist buttons (back comments list,forward comments list)
var pb=page.findObject2("/database5_17");
pb.buttonMode=true;
var pb=page.findObject2("/database5_18");
pb.buttonMode=true;

}

function showOneOf()
{
// set the a message like this: 1-10 of 32456
var c=page.findObject2("/database5_12");
if (c!=null)
{
c.text=global.startIndex+"-"+(global.startIndex+global.maxResults-1)+" of "+global.totalResults;
}
}


function searchVideos()
{
/*
here we send the search request to youtube
*/

//Alert.show(global.serv);

var searchString=global.t.text;
var startIndex=global.startIndex;
var maxResults=global.maxResults;

//global.serv.service.url=global.serv.service.url + "?vq=" + searchString + "&max-results=10";
//global.serv.call(null,"serverResponse","serverError");

var params=new Object();
params["vq"]=searchString;
params["max-results"]=maxResults;
params["format"]=5; // check this video format
params["start-index"]=startIndex;
global.serv.call(params,"serverResponse","serverError");

} // end of search videos function


function create_vBox()
{
var cw=page.findObject2("/database5_3");

// creates a vBox which will be the container for the video list
var vb=cw.content.application.new_vBox();
// set styles for vBox
vb.setStyle("borderStyle", "solid");
vb.setStyle("borderColor", 0x000000);
vb.setStyle("borderThickness", 1);
vb.setStyle("verticalGap", 1); // vertical space between childrens

vb.height=919;
vb.width=430;
vb.x=463;vb.y=97;
vb.setStyle("backgroundColor", 0xffffff);
page.content.addChild(vb);
global.vb=vb;


} // end of function create_vBox


function clearVideoList()
{
if (global.vb!=null)
global.vb.removeAllChildren();


}


function buildVideoList()
{
/*
this function take the data of the videos and build a nice
video list
*/

clearVideoList();

// get a reference to the cWidget
var cw=page.findObject2("/database5_3");

// get a reference to the vertical box created
var vb=global.vb;
if (vb==null)
{
Alert.show("vbox for video list not created");
return;
}

// loop over our video list
for (var i=0; i < global.videos.length ; i++)
{
// this is the i-esimal video of the list

// creates an image object to show a thumbnail for the video
var im=cw.content.application.new_image();
im.source=global.videos[i].thumbnail;
im.id="im"+i;
//im.addEvents("click");
im.y=6;im.x=4;
im.height=150;im.width=150;

// create a text object to show some text of the video
var text=cw.content.application.new_text();
text.htmlText=""+global.videos[i].title+""+"\n"+global.videos[i].description;
text.y=im.y;text.x=im.x+im.width+2;
text.height=100;
text.width=250;
text.setStyle("color", 0x000000);
text.id="text"+i;
text.truncateToFit=true;
//text.addEvents("click");
text.toolTip=global.videos[i].title+"\n"+global.videos[i].description;
text.mouseChildren=false;

/*
// create a play button
var but=cw.content.application.new_button();
but.label="play";
but.height=15;
but.x=90;but.y=140;
but.id="button"+i;
but.visible=false;
but.addEvents("click");
but.data=i;
*/

// create a canvas an locate every above object inside it
var can=cw.content.application.new_canvas();
can.setStyle("backgroundColor", 0xffffff);
can.setStyle("borderStyle", "none");
can.setStyle("borderColor", 0x000000);
can.setStyle("borderThickness", 1);
can.addChild(im);
//can.addChild(but); // si el boton es agregado despues del text inhibe el funcionamiento de los hyperlinks.
can.addChild(text);

can.height=im.y+im.height-30;
can.width=text.x+text.width+4;
can.id="canvVideoList_"+i;
// next line: the events of the canvas (rollover,rollOut, etc.) will begin with videoList prefix
can.addEvents("rollOver|rollOut|click|mouseWheel",'|','videoList');
can.hScrollPolicy("off");
can.vScrollPolicy("off");
can.buttonMode=true;

// add the canvas with its childrens to the container vBox
vb.addChild(can);
}


} // end of function buildVideoList