Pages

Friday, June 6, 2008

Flex embedded youtube player

There is a new version 1.1, Click on this entry to go to that version.
In this blog I will provide you the Adobe Flex code to create your own embedded youtube player which you can use in own website. You don't have to use a proxy or php script. You only has to update a xml with the youtube video urls. This xml is loaded in a tree and just click on an entry. The selected video is shown in the window. You can display your own text over the video too.


The xml with the youtube videos looks like this

<videos category="overview">
<category category="2008">
<video category="auto cross movie" url="http://www.youtube.com/v/VLlrpOUO3Qs"/>
</category>
<category category="European">
<year category="2007">
<video category="Autocross Championship - Murça 1" url="http://www.youtube.com/v/8TZgXfqpd5I"/>
</year>
</category>
<category category="Netherlands">
<year category="2007">
<video category="EUROPOKAL AutoCross" url="http://www.youtube.com/v/kprW-snP5oI"/>
<video category="VEKA NK AutoCross Visvliet" url="http://www.youtube.com/v/5OxVm-p0mC0"/>
</year>
</category>
</videos>

You can easily extend this xml with extra levels or video's you only have to add a new element with an attribute with the name category. For a you tube video entry you have to add two attributes category and url.
Here is the source code
The main code

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
backgroundGradientAlphas="[1.0, 1.0]"
backgroundGradientColors="[#CCCCCC, #CCCCCC]"
creationComplete="service.send()" height="700" width="875">

<mx:Style>
@font-face {
src:url("assets/arial.ttf");
font-family: Arial;
}

.timeStyle {
color: #FFFFFF;
font-family: Arial;
font-size: 12;
}

.playPauseStyle {
/* play button skins */
skin: Embed('assets/control_play.png');
downSkin: Embed('assets/control_play_blue.png');

/* pause button skins */
selectedUpSkin: Embed('assets/control_pause.png');
selectedOverSkin: Embed('assets/control_pause.png');
selectedDownSkin: Embed('assets/control_pause_blue.png');
}

.stopStyle {
skin: Embed('assets/control_stop.png');
downSkin: Embed('assets/control_stop_blue.png');
}

.controllerStyle {
bottom: 5;
left: 5;
right: 5;
paddingBottom: 5;
paddingLeft: 5;
paddingRight: 5;
paddingTop: 5;
alpha: 0;
background-color: #000000;
background-alpha: 0.5;
}
</mx:Style>


<mx:Script>
<![CDATA[
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
import mx.collections.HierarchicalData;
import mx.collections.XMLListCollection;
import mx.events.MetadataEvent;
import mx.utils.ObjectUtil;
import mx.events.VideoEvent;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;

[Bindable]
private var youtubeOverLay:String = "You tube player";


private function videoDisplay_metadataReceived(evt:MetadataEvent):void {
var arr:Array = [];
var item:String;
var meta:Object = evt.info; // videoDisplay.metadata;
var value:*;
for (item in meta) {
if (ObjectUtil.isSimple(meta[item])) {
if (meta[item] is Array) {
value = "[Array]";
} else {
value = meta[item]
}
arr.push({name:item, value:value});
}
}
arr.sortOn("name", Array.CASEINSENSITIVE);
dataGrid.dataProvider = arr;
// dataGrid.visible = true;
}

private function showControls():void {
fadeIn.play([controls]);
}

private function hideControls():void {
fadeOut.play([controls]);
}

private function videoDisplay_playheadUpdate(evt:VideoEvent):void {
var pTime:Date = new Date(videoDisplay.playheadTime * 1000 || 100);
var tTime:Date = new Date(videoDisplay.totalTime * 1000);
time.text = dateFormatter.format(pTime) + " / " + dateFormatter.format(tTime);
// time2.text = "Tijd " + dateFormatter.format(pTime) + " / " + dateFormatter.format(tTime);

}

private function playPauseButton_click(evt:MouseEvent):void {
if (videoDisplay.playing) {
videoDisplay.pause();
} else {
videoDisplay.play();
}
}

private function stopButton_click(evt:MouseEvent):void {
videoDisplay.stop();
}

private function doStateChange(evt:VideoEvent):void {


switch (evt.currentTarget.state) {
case VideoEvent.CONNECTION_ERROR:
evt.currentTarget.visible = false;
Alert.show(evt.currentTarget.source, "Unable to connect to video");
break;
}
}


private var vidRequest:YouTubeVideo;
private var flvURL:String;
private var youtubeXml:XML;

public function getVideoURL():void
{
vidRequest = new YouTubeVideo(adg1.selectedItem.@url);
vidRequest.addEventListener(YouTubeVideoEvent.COMPLETE, onVideoComplete);
}

private function onVideoComplete(evt:YouTubeVideoEvent):void
{
flvURL = evt.video;
videoDisplay.source = flvURL;
videoDisplay.load();
copyToClipboard();
}

private function copyToClipboard():void
{
flash.system.System.setClipboard(flvURL);
}

private function resultHandler(event:ResultEvent):void {
youtubeXml = event.result as XML;

// init the tree
adg1.dataProvider= new HierarchicalData(youtubeXml);
var columns:Array = [];
var col:AdvancedDataGridColumn = new AdvancedDataGridColumn();
col.dataField = "@category";
col.headerText = "Video";
columns.push(col);
adg1.columns = columns;


}

]]>
</mx:Script>

<mx:HTTPService id="service" url="videos.xml"
result="resultHandler(event)"
resultFormat="e4x"
useProxy="false"
showBusyCursor="true" />

<mx:Fade id="fadeIn" alphaFrom="0.0" alphaTo="1.0" />
<mx:Fade id="fadeOut" alphaFrom="1.0" alphaTo="0.0" />

<mx:DateFormatter id="dateFormatter" formatString="NN:SS" />



<mx:HBox width="100%" borderColor="#CCCCCC" backgroundColor="#CCCCCC">
<mx:VBox>
<mx:HBox>
<mx:ApplicationControlBar width="100%">
<mx:Button label="expand all" click="adg1.expandAll()" />
<mx:Button label="collapse all" click="adg1.collapseAll()" />
</mx:ApplicationControlBar>
</mx:HBox>


<mx:AdvancedDataGrid x="75" y="27" id="adg1" width="300" height="500" selectionMode="singleRow"
click="getVideoURL()" themeColor="#91280B" creationComplete="adg1.expandAll();">
</mx:AdvancedDataGrid>


</mx:VBox>
<mx:VBox width="100%" height="100%">
<mx:VBox width="100%">
<mx:Text text="{adg1.selectedItem.@category}" fontSize="16" width="100%" fontWeight="bold" color="#91280B"/>
<mx:Text text="Move your mouse on the video to control it" fontSize="12" width="100%" fontWeight="bold" color="#000000"/>

</mx:VBox>

<mx:Canvas rollOver="showControls()" rollOut="hideControls()">
<mx:VideoDisplay id="videoDisplay"
autoPlay="true"
visible="true"
ready="videoDisplay.visible = true; progressBar.visible = true ; "
metadataReceived="videoDisplay_metadataReceived(event);"
playheadUpdate="videoDisplay_playheadUpdate(event)"
stateChange="doStateChange(event);" height="400" width="500" />
<mx:HBox id="controls" styleName="controllerStyle" alpha="0.0">
<mx:Text text="{youtubeOverLay}" x="10" y="50" fontSize="12" width="100%" fontWeight="bold" color="#91280B"/>

<mx:Button id="playPauseButton" styleName="playPauseStyle" toggle="true" selected="{videoDisplay.playing}" click="playPauseButton_click(event)" />
<mx:Button id="stopButton" styleName="stopStyle" click="stopButton_click(event)" />
<mx:Spacer width="100%" />
<mx:Label id="time" styleName="timeStyle" />
</mx:HBox>
</mx:Canvas>


<mx:VBox width="100%">
<mx:ProgressBar id="progressBar" color="#91280B" barColor="#CCCCCC"
visible="false" width="{videoDisplay.width}"
mode="polled"
source="{videoDisplay}"
label="%1 of %2 KB loaded (%3%%)"
conversion="1024"
labelPlacement="center" />
<!-- <mx:Label id="time2" styleName="timeStyle" /> -->

</mx:VBox>
<mx:HBox>
<mx:Button id="aan" visible="true" click="dataGrid.visible = true; aan.visible = false; uit.visible = true;" label="Details on"/>
<mx:Button id="uit" visible="false" click="dataGrid.visible = false; uit.visible = false; aan.visible = true;" label="Details off"/>
</mx:HBox>
<mx:DataGrid id="dataGrid" visible="false" width="100%">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name:" sortable="false" />
<mx:DataGridColumn dataField="value" headerText="Value:" sortable="false" />
</mx:columns>
</mx:DataGrid>
</mx:VBox>
</mx:HBox>
</mx:Application>

11 comments:

  1. This is great. I was lookin for something that would be a bridge between the AS2 and AS3 code to support the Youtube API, but this is even better.

    My main concern is that this is against the terms of Youtube's API (you dont see the Youtube logo or any indication where the video is from) and that suddenly you might be blocked. Although I'm not quite sure how they would do that besides a cease and desist on your site.

    Any thoughts on that?

    ReplyDelete
  2. Hi,

    I am doing it for month now, in youtube you see this like it is embedded in a normal way.

    Let's hope they can't see the difference between this and normal embedding.

    ReplyDelete
  3. I've based a Flex application on this code, and all of the sudden it stopped working (and this demo doesn't seem to be working anymore either).
    Is it something that changed with the YouTube API? any ideas what I can do to make it work once more?
    thanks,

    ReplyDelete
  4. Hi.

    It seems that I need to retrieve the token for the youtube download first and then pass this to the get_video.php script.

    like this
    http://www.youtube.com/get_video.php?video_id=QNDt3bGi4GA&t=OEgsToPDskJzxr4efdP75GmNsyNlKV7t&fmt=5

    http://www.youtube.com/get_video_info?video_id=QNDt3bGi4GA
    this will give me the token.

    I will try to make an new example

    ReplyDelete
  5. Please download the sourcecode of youtube player 1.1 then it's working again.

    thanks Edwin

    ReplyDelete
  6. Hi, this is excellent for a project i'm working on. I've installed the 1.1 version and added the youtube_proxy.php to my site. When I build the project i get nothing. Is it just me?

    ReplyDelete
  7. Hi, strange.

    is your swf and php script on the same site. And does the player works fine and maybe you can debug the app and see if you get some data from youtube.

    thanks

    ReplyDelete
  8. Hello Edwin.
    Thanks for posting the code.

    I just tried to include the src code into my existing Flex project framework.

    My first attempt in compiling the code gave me the following compile-time error:


    1046: Type was not found or was not a compile-time constant: YouTubeVideoEvent. KioskNew/src/containers/windows YouTubePlayer.mxml


    for the following line in the .mxml code:


    private function onVideoComplete(evt:YouTubeVideoEvent)


    It seems that th compiler can NOT find the type YouTubeVideoEvent, even though i have the following two 'import' statements in the .mxml file:


    import com.foo.scripts.YouTube.YouTubeVideo;

    import com.foo.scripts.YouTube.YouTubeVideoEvent;


    So, I am not sure why the compiler can not see the 'type' YouTubeVideEvent.

    Perhaps I am not doing something trivial correctly (I am relatively new to Flex).

    Thanks in advance for your advice.

    Regards,
    DT

    ReplyDelete
  9. Hi,

    This code is not working anymore because Google changed last april some stuff. I need to make a new workaround first

    thanks Edwin

    ReplyDelete
  10. Hi Edwin.

    Thx 4 responding 2 my post. I look fwd to trying the upcoming version.

    Regards,
    DT

    ReplyDelete
  11. Hi,
    I made a new version which work perfectly with youtube, it uses javascript on the client side. http://biemond.blogspot.com/2009/12/flex-embedded-youtube-player-12.html

    thanks

    ReplyDelete