3VOOR12 Luisterpaal widget stuurt Now Playing info uit


maandag, december 15, 2008

3VOOR12 is erg blij met haar Luisterpaal widget. Menig Hyves profiel, Mac Dashboard en iGoogle of Netvibes startpagina is versierd met deze aanwinst :) . De Luisterpaal widget zorgt ervoor dat je niet persé naar de 3VOOR12 website hoeft om alle Luisterpaal albums te kunnen beluisteren.

Now playing

Aan programmeurs en andere mashup fanaten biedt de Luisterpaal widget nu iets extra’s: het afvangen van ‘now playing’ informatie met ActionScript (Flash) of JavaScript. Ga je gang, mashup de 3VOOR12 Luisterpaal widget! Zoals verteld in een artikel over mashups op het VPRO Kenniscentrum blog, kunnen mashups voor verrijking zorgen. Door via API’s verkregen informatie van andere websites te combineren met jouw data krijg je een goedgevulde en (hopelijk) waardevolle mashup site.

De Luisterpaal widget komt mashups nu tegemoet door middels ‘events’ aan ActionScript of JavaScript door te geven wat de gebruiker luistert. Met die informatie kan je vervolgens doen wat je wilt. Toon extra informatie naast de Luisterpaal van Flickr, Wikipedia en Youtube of scrobble het voor mijn part naar Last.fm (graag zelfs en laat het dan weten! ;) )

Geen zin om te lezen wat er nu kan, maar wil je wel graag voorbeelden zien, kijk dan op de voorbeeldpagina’s van een ActionScript(2 of 1/2/3 GEUPDATE ) of JavaScript mashup met de 3VOOR12 Luisterpaal widget.

Vier events

Er kunnen vier Luisterpaal events worden afgevangen:

1. START
Het START event geeft aan dat er een nummer begint. Elk start event wordt bijgestaan door een track object met

  • titel
  • artiest
  • album
  • album URL (link naar het Luisterpaal album op 3VOOR12)
  • albumhoes URL
  • positie van het nummer op het album
  • duur in seconden

2. STOP
Er is expliciet op ’stop’ gedrukt. Eigenlijk houdt elk START ook een impliciete stop van het vorige nummmer in.

3. PAUSE
Het nummer is gepauzeerd.

4. RESUME
Het gepauzeerde nummer wordt hervat.


Implementatie

Hieronder volgt de implementatie voor zowel een JavaScript als ActionScript client en elke implementatie wordt bijgestaan door een voorbeeld mashup.

Beide implementaties beginnen met het tonen/inladen van de Luisterpaal. Hiervoor gebruik je de volgende SWF URL:

http://download.omroep.nl/vpro/luisterpaal/widgets/LuisterpaalEvents.swf

LuisterpaalEvents.swf is het Flash bestand dat de standaard Luisterpaal inleest en events hiervan doorstuurt naar de client. De SWF URL kan aangeroepen worden met een aantal parameters:

- showbackground=false
Zet de grijsomrande witte achtergrond uit

- environment=<String>
Voor logdoeleinden. Geeft normaliter aan of de widget in bv iGoogle, Netvibes of Mac Dashboard wordt gebruikt.
Gelieve leeg te laten of een eigen te onderscheiden naam gebruiken. Dat laatste is handig voor onze statistieken, maar ook voor jou om te weten te komen hoe goed je mashup gebruikt wordt.

- oninit=<String>
Specifiek voor JavaScript clients. Zie ‘Implementatie JavaScript’.

Implementatie JavaScript

De implementatie voor JavaScript begint bij het tonen van de Luisterpaal. Gebruik de volgende URL:

http://download.omroep.nl/vpro/luisterpaal/widgets/LuisterpaalEvents.swf?oninit=<String>

Een belangrijke parameter voor JavaScript is oninit=. Hierachter vul je de naam in van de JavaScript functie die uitgevoerd moet worden als de Luisterpaal beschikbaar is om events door te geven. Pas dan zijn namelijk de volgende twee functies aan te roepen op de Luisterpaal:

addLPEventListener(event, callback)

@param event het event om af te vangen. Waarde “START”, “STOP”, “PAUSE” of “RESUME”.
@param callback de naam van de javascript functie die moet worden aangeroepen

removeLPEventListener(event, callback)

@param event het event om de afvanging van te stoppen. Waarde “START”, “STOP”, “PAUSE” of “RESUME”.
@param callback de naam van de javascript functie die niet meer moet worden aangeroepen

De callback functie voor het START event wordt bijgestaan door één argument. In JavaScript is dit een JSON object met de volgende syntax:

{
	type : "String", /* één van START, STOP, PAUSE of RESUME */
	track:
	{
		name: escaped("String"),
		artist: escaped("String"),
		album: escaped("String"),
		albumUrl: "String",
		albumCover: "String",
		trackNumber: Number,
		duration: Number
	}
}

In de praktijk kan de implementatie er als volgt uitzien. Ik maak hierbij voor het gemak even gebruik van SWFObject voor de Flash Player detectie en injectie en de jQuery library voor handige JavaScript notatie.


<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="swfobject.js"></script>

<div id=”luisterpaalevents”></div>
<div id=”metadata”></div>

<script type=”text/javascript”>

var LUISTERPAAL;

/*
	Als de pagina is geladen wordt de Luisterpaal Flash geïnjecteerd
        in de 'luisterpaalevents' div.
	De Luisterpaal is 240 pixels breed en 320 hoog.
*/
$(function(){
	var l = (new SWFObject("http://download.omroep.nl/vpro/luisterpaal/"+
                 "widgets/LuisterpaalEvents.swf?oninit=inited","luisterpaal","240","320","8"));
	l.addParam("allowScriptAccess", "always");
	l.write("luisterpaalevents");
});


/* Dit is de callback functie die wordt aangeroepen wanneer de Luisterpaal Flash klaar is om events uit te sturen */

function inited(){
       LUISTERPAAL = (typeof window["luisterpaal"] != "undefined")? window["luisterpaal"] :
                               document["luisterpaal"];

       /* voeg een eventlistener toe voor het START event */
       LUISTERPAAL.addLPEventListener("START", "start");
}


/* Het start event wordt afgevangen en track metadata wordt geïnjecteerd onder de Luisterpaal in de div met id 'metadata' */

function start(e){
	$('#metadata').html("START event voor "+
	         unescape(e.track.name) +" door "+
		unescape(e.track.artist) +
		" ("+ unescape(e.track.album) +", track nummer "+
		e.track.trackNumber	+" ) "+
		e.track.duration +" sec.<br />"+
		"Beluister het album op <a href='"+ e.track.albumUrl +
                  "'>3VOOR12.vpro.nl</a><br />"+
		"<img src='"+ e.track.albumCover +"' />");
}


</script>

JavaScript mashup voorbeeld

Een volledig voorbeeld van een JavaScript/Luisterpaal mashup vind je hier.

 

Implementatie ActionScript

De implementatie voor ActionScript kan op 2 manieren:

  1. via mx.utils.Delegate (ActionScript 2)
  2. via LocalConnection (ActionScript 1,2 en 3) GEUPDATE

1. mx.utils.Delegate (ActionScript 2)
Deze ActionScript 2 variant begint bij het binnenhalen van de Luisterpaal dmv de volgende URL:

http://download.omroep.nl/vpro/luisterpaal/widgets/LuisterpaalEvents.swf

Wanneer de Luisterpaal gedownload is, hierin variabele LuisterpaalEvents beschikbaar is en de functie LuisterpaalEvents.isInited() Boolean true teruggeeft zijn de volgende 2 functies beschikbaar:

addLPEventListener(event, callback)

@param event het event om af te vangen. Waarde “START”, “STOP”, “PAUSE” of “RESUME”.
@param callback een mx.utils.Delegate callback functie die moet worden aangeroepen

removeLPEventListener(event, callback)

@param event het event om de afvanging van te stoppen. Waarde “START”, “STOP”, “PAUSE” of “RESUME”.
@param callback een mx.utils.Delegate callback functie die niet meer moet worden aangeroepen

De callback functie voor het START event wordt bijgestaan door één argument. Dit argument is een object met de volgende eigenschappen:

{
	type : "String", /* één van START, STOP, PAUSE of RESUME */
	track: LuisterpaalTrack
}

Een instantie van LuisterpaalTrack heeft de volgende functies:

getName(): String
getAlbum(): String
getAlbumUrl(): String
getAlbumCover(): String
getTrackNumber(): Number
getDuration(): Number

In de praktijk kan de implementatie er zo uitzien.

import mx.utils.Delegate;

System.security.allowDomain('download.omroep.nl');
/* belangrijk om de Luisterpaal jouw callback functies
    aan te kunnen laten roepen */

var LUISTERPAAL:MovieClip;

var m:MovieClip = _root.createEmptyMovieClip("luisterpaalcontainer",
                               _root.getNextHighestDepth());
     m._lockroot = true;	

var ml:MovieClipLoader = new MovieClipLoader();

var l:Object = new Object();
     l.onLoadInit = function(trgt:MovieClip){
        LUISTERPAAL = trgt;
	LUISTERPAAL.onEnterFrame = function(){

	   if(typeof LUISTERPAAL.LuisterpaalEvents != "undefined"){
	     if(LUISTERPAAL.LuisterpaalEvents.isInited()){

	       delete LUISTERPAAL.onEnterFrame;

	        LUISTERPAAL.LuisterpaalEvents.addLPEventListener(
                  LUISTERPAAL.START,
		  Delegate.create(this, function(e){
		     trace(e.track.getArtist() +" speelt "+
                             e.track.getDuration() +
                             " seconden lang "+ e.track.getName() +"!");
		     trace("Nummer "+ e.track.getTrackNumber()
                             +" van het album "+
                             e.track.getAlbum() +"!");
		     trace("");
		  })
		);
	    }
	 }
       }
    };

ml.addListener(l);
ml.loadClip("http://download.omroep.nl/vpro/luisterpaal/widgets/LuisterpaalEvents.swf", m);
stop();

mx.utils.Delegate mashup voorbeeld
Een volledig voorbeeld van een ActionScript 2 Luisterpaal mashup vind je hier.

2. LocalConnection (ActionScript 1,2 en 3)

Middels het LocalConnection object in Flash is er communicatie mogelijk tussen meerdere LocalConnection instanties op dezelfde computer. De communicatie kan plaatsvinden in 1 SWF bestand, tussen verschillende SWF bestanden (in verschillende browsers) en zelfs tussen een AIR desktop applicatie en een Flash website. Ook de 3VOOR12 Luisterpaal is uitgebreid met een LocalConnection object tbv now playing info. Voorlopig betreft het hier wel de speciale LuisterpaalEvents.swf versie. Deze zal in je mashup aanwezig moeten zijn of geopend in andere pagina/browser/applicatie, etc.

Voor het onderstaande voorbeeld kan daarvoor gebruik worden gemaakt van de mx.utils.Delegate mashup pagina. Maak vervolgens een eigen Flash app met een LocalConnection object. Op dit receiving LocalConnection object kunnen de volgende 4 methodes worden aangeroepen door de Luisterpaal:

start
De start methode wordt bijgestaan door 1 Object argument:

track:
{
	name: "String",
	artist: "String",
	album: "String",
	albumUrl: "String",
	albumCover: "String",
	trackNumber: Number,
	duration: Number
}

stop

pause

resume

In de praktijk kan dat er als volgt uitzien (ActionScript 2):

var localConnection:LocalConnection = new LocalConnection();
	localConnection.allowDomain = function(sendingDomain:String){
		return true;//of filter op basis van sendingDomain
	}
	localConnection.start = function(track:Object){
		trace("De Luisterpaal speelt: \n"+
		track.name +" van "+ track.artist);
	}
	localConnection.stop = function(){
		trace("De Luisterpaal is gestopt");
	}
	localConnection.pause = function(){
		trace("De Luisterpaal is gepauzeerd");
	}
	localConnection.resume = function(){
		trace("De Luisterpaal is hervat");
	}

var connectionName:String = "_nl.vpro.drievoortwaalf.luisterpaal";
if(localConnection.connect(connectionName)){
	trace("Klaar om Luisterpaal events af te vangen middels LocalConnection "+ connectionName);
}else{
	trace("LocalConnection niet verbonden met "+ connectionName);
}
stop();

Opmerkingen
‘allowDomain’ is een functie die in ActionScript 1 en 2 een callback is en true terug moet geven wanneer het ’sending’ domein de methodes op de ‘receiving’ instantie mag aanroepen. Voor ActionScript 3 werkt deze methode echter hetzelfde als System.security.allowDomain

Voor ‘connect’ wordt standaard de connectienaam ‘_nl.vpro.drievoortwaalf.luisterpaal’ gebruikt. Mocht je zelf LuisterpaalEvents.swf embedden dan kan je een eigen connectienaam verzinnen en hem meegeven aan de swf middels flashvar ‘localconnection’. Begin de naam wel met een underscore, omdat Flash anders de naam uitbreidt met een domeinnaam als prefix.

LocalConnection mashup voorbeeld
Een volledig voorbeeld van een LocalConnection Luisterpaal mashup vind je hier.

 

Happy Mashupping

Mocht je interessante mashups hebben gemaakt met de Luisterpaal, laat het ons dan vooral weten. Met liefde promoten we ze op onze websites. Geef bij vragen uiteraard ook een gil!

21 Responses to “3VOOR12 Luisterpaal widget stuurt Now Playing info uit”


  1. eerkmans Says:

    Geweldig nieuws!
    Ik ga die flash API eens even uitproberen!

  2. frank Says:

    @eerkmans mooizo! Nav een tweet van @UnitZeroOne ( http://twitter.com/UnitZeroOne/status/1058744483 ), wordt hij zo snel mogelijk met een LocalConnection API uitgebreid. Wel wat makkelijker, ook voor AS3 implementatie.

  3. ad Says:

    goed!

  4. Eelco Lempsink Says:

    Ik heb een (zeer rudimentaire) last.fm scrobbler gebouwd met de nieuwe API. Het is nog lang niet af (en ik heb nog geen geldig client id), maar de code is te vinden op http://github.com/eelco/luisterpaal.fm en een demo draait op http://code.tupil.com/luisterpaal/

    De demo update wel je ‘now playing’ status, maar de submissions zullen niet op je profiel verschijnen, daarvoor moet ik nog even wachten op een client id van last.fm.

  5. Eelco Lempsink Says:

    Inmiddels is de code wel af en heb ik ook een client id. Dus het scrobbelen kan beginnen! :) Zie http://code.tupil.com/luisterpaal/ (ik ben aan het nadenken over een permanentere plek.)

  6. frank Says:

    @Eelco hulde, hulde, hulde! Ik krijg nu alleen nog een error “Key ’session’ not found in object” :) (met Firefox), maar ik kan niet wachten tot het werkt, dan zullen we je op handen dragen!

  7. eerkmans Says:

    hey, ik ben wat aan het sjoemelen met de luisterpaal events (leuk!) maar ik vroeg me af of het ook mogelijk is om “now listening to” info te krijgen van Luisterpalen die je elders open hebt staan, bv. op de 3voor12 site of in je iGooglez.

    Ook lijkt het me leuk als je toch een luisterpaal instance hebt, dat je dan ook de afspeel functies kan aanroepen. (speel album 3 track 4 of zoiets).

  8. Eelco Lempsink Says:

    @frank Ja, dat doet’ie heel soms (een sessie token van Last.fm krijgen gaat dan mis.) Of werkt het nog steeds niet wanneer je het nog eens probeert?

    Ik heb het netter afhandelen (automatisch opnieuw proberen) in ieder geval op de TODO lijst gezet.

  9. frank Says:

    @eelco hij werkt idd! Supergaaf!! Ik ga het morgen ff over de afdelingen verspreiden. Vind je het goed als ik er een blogpostje aan wijd?

    @eerkmans cool! Ben benieuwd. Over now-listening voor de site en iGoogle, dat laatste (en eigenlijk ook Hyves ed) moet kunnen, maar dan moet ik even een extra developers iGoogle URL (en embed-code) posten op http://3voor12.vpro.nl/service/tools . Voor de site gaat dat nog niet, dan moet je een (browser)plugin bouwen zoals Twones.com dat doet.

    Over het aansturen van de Luisterpaal zit ik nog in dubio, omdat je op die manier ook de Luisterpaal widget kan omzeilen en compleet je eigen onafhankelijke Luisterpaal kan maken…

  10. Eelco Lempsink Says:

    @frank Uiteraard, geen probleem, integendeel :) Ik heb net nog even een UserVoice feedback tabje toegevoegd, dus alle extra ‘ogen’ zijn welkom ;)

  11. Redmar Says:

    Kijk dit is nog eens goed nieuws! Nou nog de combinatie met de widget voor mac os x en dan ben ik helemaal tevreden!

  12. Eelco Lempsink Says:

    @Redmar, je kunt (relatief) eenvoudig zelf een widget maken:

    1. Start de luisterpaal een keer op met Safari.
    2. Selecteer “File -> Open in Dashboard…” en knip de luisterpaal uit
    3. Stel bij de settings van de widget in dat audio altijd hoorbaar moet zijn.

    Tada!

    Veel succes :)

  13. Eelco Lempsink Says:

    Oh ja, op dit moment is het toeval dat je user interface precies genoeg op de widget past. Ik zet het maken van een ‘widget vriendelijke’ UI op de TODO lijst.

  14. Frank Bosma Says:

    Inmiddels bevat de LuisterpaalEvents.swf ook een LocalConnection implementatie om zowel in ActionScript 1,2 als 3 een mashup te maken! Zie http://weblogs.vpro.nl/digitaal/2008/12/15/3voor12-luisterpaal-widget-stuurt-now-playing-info-ui/#localconnection

  15. Tupil maakt Luisterpaal.fm een feit | VPRO Digitaal Says:

    [...] niet zo lang geleden blogde ik over de mogelijkheid om de 3VOOR12 Luisterpaal widget te kunnen mashuppen om hem bijvoorbeeld [...]

  16. Redmar Says:

    Dank Eelco!

  17. Redmar Says:

    Mmmm het werkt toch niet helemaal zoals het moet denk ik. Hij pakt namelijk alleen maar het eerste nummer van een cd. Hij blijft dan hangen op listening now… en gaat niet over op een ander nummer. Zowel bij Firefox en Safari… Weet je waar dit aan kan liggen?

  18. Redmar Says:

    En nog een kleine aanvulling (jammer dat je berichten hier niet kunt bewerken); Hij pakt volgens mij alleen het huidige nummer (met enige vertraging). Hij scrobbelt bij mij dus niet.

  19. frank Says:

    @redmar Hoi! Op Eelco’s Luisterpaal.fm mashup staat een feedback knopje, welke linkt naar http://luisterpaal.uservoice.com/pages/general?referer_type=popin Daar kan je feedback geven die Eelco ook direct zal zien. Daarnaast heb je daar denk ik inderdaad meer mogelijkheden wat betreft comment editing :) Thanks voor je interesse en enthousiasme in ieder geval!

  20. Redmar Says:

    Het werkt! Het uitzetten van de last.fm scrobbeller (wat een onmogelijk woord om op een goede manier te vervoegen trouwens ;) loste het probleem op.

  21. Wilko Says:

    Ik heb de 3v12-scrobbler in een aparte applicatie gezet door middel van Fluid (http://fluidapp.com/) - vind ik beter werken dan een widget in het dashboard. Gaat uitstekend :D
    Zijn er overigens ook plannen om zoiets te maken voor bv. de Radio6-luisterpaal? Ik zou zeker interesse hebben.
    iig thanks voor deze scrobbler :) groet W.

Leave a Reply


In order to submit a comment, you need to mention your name and your email address (which won't be published). And ... don't forget your comment!

Comment Form