26 gennaio 2010

Embed del Player Youtube in Flex

di Marcello Ruta

Tool utilizzati: Flex 3

Requisiti: Cononoscenze di Actionscript 3.0

Assets Finali: TubeFlexPlayer.mxml, youtube.xml, TubePlayer.as

Flex SDK: 3.4

Reference YouTube Api: http://code.google.com/intl/it-IT/apis/youtube/flash_api_reference.html

Questo tutorial diciamo che rappresenta la prosecuzione di quello precedente “Video di YouTube dentro il nostro Player Personalizzato” sviluppato con Flash, in questo vedremo come sviluppare la medesima situazione ma con Flex. Inoltre in questo esercizio implementeremo maggiori funzionalità rispetto a quello precedente. La sorgente dei dati è un file xml ed avremo i video divisi in categorie.

Player Finale

La nostra interfaccia sarà composta da 3 HSlider, uno per il volume, uno per il Resize del player ed uno per mostrare l’avanzamento del video. Poi avremo 6 Button, uno per il Mute dell’audio e uno per l’Unmute, gli altri servono per stoppare (Stop) totalmente il video, per caricare un video (Load), per mettere in puasa il video e uno per metterlo di nuovo in esecuzione. Nella parte destra abbiamo una ComboBox per le categorie e sotto un ListBox per poter scegliere quale video vogliamo vedere.

Nel primo step inizieremo a vedere come configurare il nostro progetto su Flex, apriamo il FlexBuilder o Eclipse e nella Navigator facciamo clic di destro New>FlexProject in alternativa File>New>FlexProject, assegniamo al nostro progetto il nome di TubeFlexPlayer quindi facciamo clic su Finish. Creato il progetto, aggiungiamo una cartellina assets dove metteremo il nostro file youtube.xml, dentro src aggiungiamo le cartelle che costituiscono il nostro package (io ho messo net/comp voi mettete quello che preferite). Adesso abbiamo terminato con le fasi preliminari, andiamo avanti con la scrittura del componente TubePlayer.

TubePlayer.as

In questo passaggio commenteremo la classe TubePlayer.as che estende la classe base UIComponent. Quindi mettiamoci all’interno del nostra cartella comp (nella Navigator) e qui facciamo clic di destro New>ActionScript Class, si aprirà l’apposita finestra dove andremo a scegliere il nome da dare alla nostra Classe nel nostro caso TubePlayer e selezioneremo la Superclass da estendere, nel nostro caso UIComponent. Fatto questo siamo pronti per scrivere il nostro codice.

N.B. Durante la scrittura della classe utilizzeremo qualche getter e setter.

Nel primo passaggio ci limiteremo a fare l’import di alcune classi:

import flash.display.*;
import flash.events.*;
import flash.net.*;
import flash.system.Security;

Dopo aver eseguito l’import di questi classi, facciamo alcuni settaggi sulla sicurezza del FlashPlayer al fine di poter eseguire normalmente l’embed del player di YouTube.

Security.allowInsecureDomain("*");
Security.allowDomain("*");

A questo punto dichiareremo un blocco iniziale di alcune variabili, con la possibilità di aggiungerne altre durante la fase di scrittura del codice.

private var tubePlayer:Object;
[Bindable]
private var loader:Loader;
private var requestUrl:URLRequest;
private var pathAPI:String = "http://www.youtube.com/apiplayer?version=3";
private var videoID:String;
private var _volume:Number = 100;
private var isMute:Boolean = false;

Tutte le variabili dichiarate sono di tipo private, quindi raggiungibili soltanto nell’ambito di questa classe.

Nel passo successivo affronteremo il caricamento delle API di YouTube.

Ecco il codice:

requestUrl = new URLRequest(pathAPI);
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit)
loader.load(requestUrl);

addChild(loader);

Nella variabile pathAPI ci sta il percorso delle api del player di youtube.
Adesso utilizzeremo un setter per impostare il videoId ovvero per far si che a loadVideoById venga assegnato un valore.

public function set videoId(value:String):void {

videoID = value;

}

dopo questo passaggio vedremo come fare alcuni settaggi sul controllo dell’audio, ovvero aumentare e diminuire il volume con un HSlider.

public function set volumeCtrl(value:Number):void {

value = Math.min(100, Math.max(value, 0));
if (value != _volume) {
_volume = value;
tubePlayer.setVolume(value);
}
}

[Bindable]
public function get volumeCtrl():Number {

return _volume;
}

i successivi passaggi consisteranno nel mettere in Mute e unMute l’audio, ecco il codice:

public function muted():void {

tubePlayer.mute();

}

public function unMuted():void {

tubePlayer.unMute();

}

a questo punto vedremo come effettuare il resize del player, ecco il codice:

private function onSetPlayerSize(w:Number, h:Number):void {

tubePlayer.setSize(w, h);
}

private function onResize(e:ResizeEvent):void {

onSetPlayerSize(this.width, this.height);
}
la funzione onResize sarà richiamata nel seguente blocco:
private function onPlayerStateChange(e:Event):void {
// Event.data contains the event parameter, which is the new player state
//state = int(Object(e).data);
this.addEventListener(ResizeEvent.RESIZE, onResize);
}

le successive funzionalità riguardano come mettere in Play, in Stop e in Pausa il video, ecco il codice:

public function onStopVideo():void {

if (tubePlayer != null) {

tubePlayer.stopVideo();

}
}

public function onPlayVideo():void {

if (tubePlayer != null) {

tubePlayer.playVideo();

}
}

public function onPauseVideo():void {

if (tubePlayer != null) {

tubePlayer.pauseVideo();

}
}

adesso aggiungiamo il codice per determinarci la durata totale del video e quella corrente, ecco il codice:

public function getTotalTime():int {

if (tubePlayer != null) {

return int(tubePlayer.getDuration());

} else {

return 0;
}

}

public function getTimeDuration():int {

if (tubePlayer != null) {

return int(tubePlayer.getCurrentTime());

} else {

return 0;
}
}

infine analizziamo la funzione onLoaderInit, che riassume in sé una serie di listener, ecco il codice:

private function onLoaderInit(e:Event):void {

loader.content.addEventListener("onReady", onPlayerReady);
loader.content.addEventListener("onError", onPlayerError);
loader.content.addEventListener("onStateChange", onPlayerStateChange);
loader.content.addEventListener("onPlaybackQualityChange", onVideoPlaybackQualityChange);

}

private function onPlayerReady(e:Event):void {
// Event.data contains the event parameter, which is the Player API ID
trace("player ready:", Object(e).data);

// Once this event has been dispatched by the player, we can use
// cueVideoById, loadVideoById, cueVideoByUrl and loadVideoByUrl
// to load a particular YouTube video.
tubePlayer = loader.content;
//load our video ID
tubePlayer.loadVideoById(videoID);

onPlayerLoaded(_volume, isMute)
}

private function onPlayerLoaded(volume:Number, isMuted:Boolean):void {
_volume = volume;
isMuted = isMute;
onSetPlayerSize(212, 159);
dispatchEvent(new Event('playerChanged'));
}

La funzione onPlayerLoaded esegue alcuni controlli e imposta la grandezza iniziale del player.

Saltando il commento di alcune function, il nostro codice alla fine sarà cosi:

package net.comp {

import flash.display.*;
import flash.events.*;
import flash.net.*;
import flash.system.Security;

import mx.core.UIComponent;
import mx.events.ResizeEvent;

Security.allowInsecureDomain("*");
Security.allowDomain("*");

[Event(name="playerChanged",event="flash.events.Event")]

public class TubePlayer extends UIComponent {

private var tubePlayer:Object;
[Bindable]
private var loader:Loader;
private var requestUrl:URLRequest;
private var pathAPI:String = "http://www.youtube.com/apiplayer?version=3";
private var videoID:String;
private var _volume:Number = 100;
private var isMute:Boolean = false;

public function TubePlayer() {
super();

/**
* Caricamento delle API del youtube player
*/

requestUrl = new URLRequest(pathAPI);
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit)
loader.load(requestUrl);

addChild(loader);
}

public function set videoId(value:String):void {

videoID = value;

}

/** Controllo del volume */
public function set volumeCtrl(value:Number):void {

value = Math.min(100, Math.max(value, 0));
if (value != _volume) {
_volume = value;
tubePlayer.setVolume(value);
}
}

[Bindable]
public function get volumeCtrl():Number {

return _volume;
}

/** Mettiamo in Mute il Player */

public function muted():void {

tubePlayer.mute();

}

public function unMuted():void {

tubePlayer.unMute();

}

private function onSetPlayerSize(w:Number, h:Number):void {

tubePlayer.setSize(w, h);
}

private function onResize(e:ResizeEvent):void {

onSetPlayerSize(this.width, this.height);
}

public function onStopVideo():void {

if (tubePlayer != null) {

tubePlayer.stopVideo();

}
}

public function onPlayVideo():void {

if (tubePlayer != null) {

tubePlayer.playVideo();

}
}

public function onPauseVideo():void {

if (tubePlayer != null) {

tubePlayer.pauseVideo();

}
}

public function onLoadVideoId(videoId:String):void {

tubePlayer.loadVideoById(videoID);

}

public function getTotalTime():int {

if (tubePlayer != null) {

return int(tubePlayer.getDuration());

} else {

return 0;
}

}

public function getTimeDuration():int {

if (tubePlayer != null) {

return int(tubePlayer.getCurrentTime());

} else {

return 0;
}
}

private function onLoaderInit(e:Event):void {

loader.content.addEventListener("onReady", onPlayerReady);
loader.content.addEventListener("onError", onPlayerError);
loader.content.addEventListener("onStateChange", onPlayerStateChange);
loader.content.addEventListener("onPlaybackQualityChange", onVideoPlaybackQualityChange);

}

private function onPlayerReady(e:Event):void {
// Event.data contains the event parameter, which is the Player API ID
trace("player ready:", Object(e).data);

// Once this event has been dispatched by the player, we can use
// cueVideoById, loadVideoById, cueVideoByUrl and loadVideoByUrl
// to load a particular YouTube video.
tubePlayer = loader.content;
//load our video ID
tubePlayer.loadVideoById(videoID);

onPlayerLoaded(_volume, isMute)
}

private function onPlayerLoaded(volume:Number, isMuted:Boolean):void {
_volume = volume;
isMuted = isMute;
onSetPlayerSize(212, 159);
dispatchEvent(new Event('playerChanged'));
}

private function onPlayerError(e:Event):void {
// Event.data contains the event parameter, which is the error code
trace("player error:", Object(e).data);
}

private function onPlayerStateChange(e:Event):void {
// Event.data contains the event parameter, which is the new player state
//state = int(Object(e).data);
this.addEventListener(ResizeEvent.RESIZE, onResize);
}

private function onVideoPlaybackQualityChange(e:Event):void {
// Event.data contains the event parameter, which is the new video quality
trace("video quality:", Object(e).data);
}

}
}

Adesso passiamo al codice MXML.

TubeFlexPlayer.mxml

In questo step vedremo come implementare il nostro player di youtube. Per prima cosa apriamo un blocco <mx:Script> dove imposteremo alcune variabili, eseguiremo l’import di alcune classi.

Adesso vediamo il codice necessario per il nostro custom player, in questo step non fornirò alcuna spiegazione giacché il codice è commentato.

<?xml version = "1.0" encoding = "utf-8"?>
<mx:Application xmlns:mx = "http://www.adobe.com/2006/mxml"
layout = "absolute"
creationComplete = "init()"
xmlns:ytb = "net.comp.*">

<mx:Script>
<![CDATA[
import net.comp.TubePlayer;
import mx.controls.Alert;

[Bindable]
private var youtube:TubePlayer
private var ytbTimer:Timer;
private var urlRequest:URLRequest;
private var urlLoader:URLLoader;
private var pathFile:String = "../assets/youtube.xml";
[Bindable]
private var xmlNode:XML;
[Bindable]
public var xmlItem:Object;

/**
* il metodo init sarà richiamato al creationComplete
* ed avvierà il nostro custom player
*/

private function init():void {

onLoadData(pathFile);

addPlayer();
configureButton();

}

/**
* Creiamo un'istanza del nostro player
* e l'aggiungiamo alla displaylist
* nello stesso tempo un timer per il calcolo del tempo trascorso
* e del tempo totale
*/

private function addPlayer():void {

youtube = new TubePlayer();
youtube.videoId = String(xmlItem);
playerYTB.addChild(youtube);

ytbTimer = new Timer(100, 0)
ytbTimer.addEventListener(TimerEvent.TIMER, totalTimeHandler);
ytbTimer.start();
}

/**
* configurazione iniziale dello stato dei pulsanti
* Play, Pause, Stop e Load
*/

private function configureButton():void {

playBtn.enabled = false;
pauseBtn.enabled = false;
stopBtn.enabled = false;
loadBtn.enabled = false;

}

/**
* togliamo la voce al nostro player
* richiamando il metodo muted()
*/

private function onMutedHandler(e:MouseEvent):void {

youtube.muted();

}

/**
* Ridiamo la voce al nostro player
* richiamando il metodo unMuted()
*/

private function unMutedHandler(e:MouseEvent):void {

youtube.unMuted();

}

/**
* Carichiamo il video assegnando l'oggetto xmlItem
* l'assegnazione dell'oggetto è di tipo String
* per questo motivo facciamo un casting dell'oggetto
* in quanto il metodo onLoadVideoId richiede un valore di tipo String
*/

private function onLoadVideo(e:MouseEvent):void {

youtube.onLoadVideoId(String(xmlItem));
playBtn.enabled = true;
pauseBtn.enabled = true;
stopBtn.enabled = true;

}

/**
* Stoppiamo il video e disabilitiamo
* i pulsanti 'playBtn' e 'pauseBtn'
*/

private function onStopHandler(e:MouseEvent):void {
youtube.onStopVideo();
playBtn.enabled = false;
pauseBtn.enabled = false;
}

/**
* Mettiamo in play il video.
*/

private function onPlayHandler(e:MouseEvent):void {

youtube.onPlayVideo();

}

/**
* mettiamo in pausa il video
*/

private function onPauseHandler(e:MouseEvent):void {

youtube.onPauseVideo();

}

/**
* Calcoliamo il tempo trascorso.
* Calcoliamo il tempo totale.
*/

private function totalTimeHandler(e:TimerEvent):void {

totalTime.text = youtube.getTotalTime().toString();
currentTime.text = youtube.getTimeDuration().toString();
videoTrack.value = youtube.getTimeDuration();
videoTrack.maximum = youtube.getTotalTime();
videoTrack.labels = ['0', youtube.getTotalTime().toString()];

}

/**
* Carichiamo il file xml
*/

private function onLoadData(url:String):void {

urlRequest = new URLRequest(url);
urlLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, onLoadXML);
urlLoader.load(urlRequest);

}

/**
* Leggiamo i nodi dell'xml
*/

private function onLoadXML(e:Event):void {

xmlNode = XML(e.target.data);
}
]]>
</mx:Script>

<mx:VBox y = "10"
x = "10">

<mx:HBox paddingBottom = "10">
<mx:Label text = "Volume" />
<!-- Slider per il controllo del volume -->
<mx:HSlider id = "ctrlVol"
change = "youtube.volumeCtrl = ctrlVol.value"
liveDragging = "true"
value = "{youtube.volumeCtrl}"
minimum = "0"
maximum = "100"
snapInterval = "1"
labels = "['0', '100']" />
</mx:HBox>

<mx:HRule width = "100%" />

<mx:HBox paddingBottom = "10"
paddingTop = "10">

<mx:Button label = "Mute"
click = "onMutedHandler(event)"
buttonMode = "true" />

<mx:Button label = "UnMute"
click = "unMutedHandler(event)"
buttonMode = "true" />
</mx:HBox>

<mx:HRule width = "100%" />

<mx:HBox paddingBottom = "10"
paddingTop = "10">
<mx:Label text = "Resize Control" />
<!-- Slider orizzontale per il resize del player -->
<mx:HSlider id = "resizeYTB"
minimum = "106"
maximum = "550"
value = "212"
change = "youtube.width=resizeYTB.value; youtube.height=resizeYTB.value*3/4"
liveDragging = "true"
snapInterval = "1"
tickInterval = "10" />
</mx:HBox>

<mx:HRule width = "100%" />

<mx:HBox paddingBottom = "10"
paddingTop = "10">

<!-- Blocco dei pulsanti per il controllo del video, Play, Pause, Stop e Load -->

<mx:Button id = "playBtn"
label = ">>"
buttonMode = "true"
click = "onPlayHandler(event)" />
<mx:Button id = "pauseBtn"
label = "||"
buttonMode = "true"
click = "onPauseHandler(event)" />
<mx:Button label = "Load"
id = "loadBtn"
buttonMode = "true"
click = "onLoadVideo(event)" />
<mx:Button label = "Stop"
id = "stopBtn"
buttonMode = "true"
click = "onStopHandler(event)" />

</mx:HBox>

<mx:HRule width = "100%" />
<mx:HBox paddingTop = "10"
paddingBottom = "10">
<mx:Label text = "Tempo Totale: " />
<mx:Label id = "totalTime" />
<mx:Label text = "Tempo Corrente: " />
<mx:Label id = "currentTime" />
</mx:HBox>

</mx:VBox>

<mx:VBox id = "playerYTB"
x = "300"
y = "10">

<mx:HSlider id = "videoTrack"
width = "100%"
snapInterval = "1"
tickInterval = "10" />
</mx:VBox>

<mx:VBox x = "870"
y = "30">

<mx:ComboBox id = "cmbCategory"
dataProvider = "{xmlNode.category}"
labelField = "@labelCat" />

<mx:List id = "listBox"
dataProvider = "{cmbCategory.selectedItem..trackId}"
change = "youtube.videoId=String(List(event.target).selectedItem), loadBtn.enabled=true"
click = "onStopHandler(event), onLoadVideo(event)"
labelField = "@title" />

</mx:VBox>
</mx:Application>

Il tutorial adesso è finito, non ci resta che testare la nostra applicazione.

Ecco la cartella con i file in allegato TubeFlexPlayer

Vota

Comments