Olivier Mengué – Code & rando

Aller au contenu | Aller au menu | Aller à la recherche

dimanche 28 septembre 2008

xmltv-fr.appspot.com est en ligne !

J'annonce xmltv-fr.appspot.com, mon grabber XMLTV qui diffuse la grille de programmes de télévision au format XMLTV.

J'avais déjà développé une solution à base de scripts shell et de feuille de style XSLT, puis un proxy en PHP il y a 6 mois, mais j'avais des problèmes de fiabilité en raison de l'hébergement chez Free.fr : un appel sur trois au service échouait. J'ai donc fait en une journée le portage en Python pour l'héberger sur Google AppEngine. Grâce à l'infrastructure de Google je ne devrait pas avoir de soucis du même type.

Pour l'instant, le flux récupéré ne correspond qu'à un seul appel au site Télérama et donc ne récupère que 3h de programmes des 6 chaînes analogiques nationales. Mais je compte bien poursuivre le portage pour arriver à l'équivalent de la version PHP puis éventuellement utiliser le stockage Google pour améliorer les performances grâce à un cache.

Pour vous faire patienter, voici un peu de doc sur l'interface du grabbber PHP :

  • /xmltv/telerama.xmltv : 3h de programme à partir de maintenant sur les 6 chaînes (c'est la seule chose qui fonctionne sur xmltv-fr.appspot.com pour l'instant).
  • /xmltv/telerama.xmltv?start=20080927220000 : 3h de programme à partir du samedi 27 à 22:00 (heure de Paris)
  • /xmltv/telerama.xmltv?channels=192,4,80,34,47,118,111,445,119,195,446,444,234,78,226,481,458,482 : 3h de programme de la TNT

J'ai écrit cette semaine une feuille de style XSLT pour faire plusieurs appels au service et combiner les résultats en un seul fichier XMLTV :

xsltproc -o tv.xml http://o.mengue.free.fr/xmltv/telerama-full.xslt http://o.mengue.free.fr/xmltv/TNT.xml

Dès que j'aurais implémenté les paramètres start et channels la même feuille de style pourra aussi fonctionner pour xml-fr.appspot.com.

MàJ 2008-09-29 : le portage est complet, l'API complète (start, channels) est disponible, donc vous pouvez utiliser la même feuille de style simplement en changeant l'URL du service. Voici un exemple où je récupère le programme des 5 prochains jours (voir le format du paramètre duration) :

xsltproc -o tv.xml -stringparam xmltv-url http://xmltv-fr.appspot.com/telerama.xmltv -stringparam duration P5D http://o.mengue.free.fr/xmltv/telerama-full.xslt http://o.mengue.free.fr/xmltv/TNT.xml

Malheureusement, je m'aperçois que je rencontre les mêmes problèmes d'accès au service : je ne peux qu'en déduire que cela vient en fait du site Télérama. À suivre…

samedi 27 septembre 2008

Playing with timezones and building my own XSLT test framework

I'm currently playing with XSLT to improve my XMLTV grabbing solution. Much fun playing with a functionnal language available in most web browsers.

I had the need to handle timezone with daylight savings to display date/times in my timezone, Europe/Paris (same as most of western Europe), which has currently the following definition (I'm not interested in history for this project):

  • Winter is UTC + 01:00
  • Summer is UTC + 02:00
  • Transition from winter to summer occurs on the last sunday of March at 01:00 UTC
  • Transition from summer to winter occurs on the last sunday of October at 01:00 UTC

So I wrote the following template date-time-Paris which is very specialized as it handles only one specific timezone, but it is very fast. I'm using only two extensions from EXSLT: date:day-in-week() and date:add().

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:tap="test:tap"
  xmlns:date="http://exslt.org/dates-and-times"
  extension-element-prefixes="date"
  >

  <!-- Transformation de l'heure UTC en heure de Paris -->
  <!-- Copyright (c) 2008 Olivier Mengué -->
  <xsl:template name="date-time-Paris">
    <!--
      Daylight savings transitions:
      - last sunday of March at 1:00 UTC
      - last sunday of October at 1:00 UTC
      Time offsets:
      - winter: +01:00
      - summer: +02:00
    -->
    <xsl:param name="date-time-Z"/><!-- UTC -->
    <xsl:variable name="len" select="string-length($date-time-Z)"/>
    <xsl:variable name="seps" select="translate($date-time-Z, '0123456789', '')"/>
    <xsl:if test="$len &lt; 11 or substring($date-time-Z, $len, 1) != 'Z' or ($seps != '--T::Z' and $seps != '--T::.Z' and $seps != '--Z' and $seps != '--TZ' and $seps != '--T:Z')">
      <xsl:message terminate="yes">date-time-Paris: date '<xsl:value-of select="$date-time-Z"/>' invalide.</xsl:message>
    </xsl:if>
    <xsl:variable name="month" select="number(substring($date-time-Z, 6, 2))"/>
    <xsl:variable name="offset">
      <xsl:choose>
        <xsl:when test="$month &lt; 3 or $month &gt; 10">1</xsl:when>
        <xsl:when test="$month &gt; 3 and $month &lt; 10">2</xsl:when>
        <xsl:otherwise>
          <xsl:variable name="transition-day" select="32 - date:day-in-week(concat(substring($date-time-Z, 1, 7), '-31Z'))"/>
          <xsl:variable name="less" select="translate(substring($date-time-Z, 8), '-T:Z', '') &lt; $transition-day*1000000+10000"/>
          <xsl:value-of select="1+number(($less and $month = 10) or (not($less) and $month = 3))"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="concat(translate(date:add($date-time-Z, concat('PT', $offset, 'H')), 'Z', ''), '+0', $offset, ':00')"/>
  </xsl:template>

The implementation is really short, however it is quite complex as XSLT 1.0 requires to uses many tricks to workaround languages limitations (no native date type, no string order, no xor operator). Here are some tips to follow the code:

  • (a xor b) is equivalent to ((a and not(b) ) and (not(a) and b)).
  • number(true()) is 1, number(false()) is 0.
  • March and October have the same number of days: 31.
  • $transition-day*10000000+10000 for october 2008 (26010000) is an number representation of 2008-10-26T01:00:00Z.
  • the second argument to date:add() is a ISO 8601 duration. Ex: PT2H (2 hours).

In fact I present here the fourth version of the code, the first one was much longer (5x) as I was using intermediate templates for computations (last-sunday-of-month, previous-sunday). Of course the key to debug, and then optimise and refactor the implementation was to start with a good test suite. The test suite is of course written in XML and embedded in the stylesheet so it can evolve with the code.



  <tap:suite name="date-time-Paris" xmlns:t="test:date-time-Paris">
    <t:t dt="2008-09-24T21:37:52Z"     r="2008-09-24T23:37:52+02:00"/>
    <t:t dt="2008-09-24T23:37:52Z"     r="2008-09-25T01:37:52+02:00"/>
    <t:t dt="2008-09-24T23:37:52.325Z" r="2008-09-25T01:37:52.325+02:00"/>
    <t:t dt="2008-10-01T00:00:00Z"     r="2008-10-01T02:00:00+02:00"/>
    <t:t dt="2008-10-26T00:59:59Z"     r="2008-10-26T02:59:59+02:00"/>
    <t:t dt="2008-10-26T01:00:00Z"     r="2008-10-26T02:00:00+01:00"/>
    <t:t dt="2008-10-31T12:00:00Z"     r="2008-10-31T13:00:00+01:00"/>
    <t:t dt="2008-11-24T21:37:52Z"     r="2008-11-24T22:37:52+01:00"/>
    <t:t dt="2008-12-31T23:30:00Z"     r="2009-01-01T00:30:00+01:00"/>
    <t:t dt="2009-01-01T00:00:00Z"     r="2009-01-01T01:00:00+01:00"/>
    <t:t dt="2009-03-01T12:00:00Z"     r="2009-03-01T13:00:00+01:00"/>
    <t:t dt="2009-03-29T00:59:59Z"     r="2009-03-29T01:59:59+01:00"/>
    <t:t dt="2009-03-29T01:00:00Z"     r="2009-03-29T03:00:00+02:00"/>
    <t:t dt="2009-03-30T12:00:00Z"     r="2009-03-30T14:00:00+02:00"/>
    <t:t dt="2009-07-01T00:00:00Z"     r="2009-07-01T02:00:00+02:00"/>
  </tap:suite>

A more complete testsuite can be generated from a local dump of the zoneinfo database (directly works on Ubuntu Hardy, however the zdump tool is missing on RHEL/CentOS):

zdump -v Europe/Paris | perl -ne 'm/ (Mar|Oct) (\d{2}) (\d{2}:\d{2}:\d{2}) (20[0-5]\d) UTC = ... (?:Oct|Mar) (\d{2}) (\d{2}:\d{2}:\d{2}) / && do { my $mm = sprintf "%02d", 3+7*($1 eq 'Oct'); print "    <t:t dt=\"$4-$mm-$2T$3\" r=\"$4-$mm-$5T$6\"/>\n"; }'

Now, we need is a way to run the test suite. In XSLT terms, we say: "to apply a template to the test data". This template will just apply a date-time-Paris call to each of the tests.

  <xsl:template match="t:t" xmlns:t="test:date-time-Paris">
    <xsl:call-template name="tap:is">
      <xsl:with-param name="got">
        <xsl:call-template name="date-time-Paris">
          <xsl:with-param name="date-time-Z" select="@dt"/>
        </xsl:call-template>
      </xsl:with-param>
      <xsl:with-param name="expected" select="@r"/>
      <xsl:with-param name="name" select="@dt"/>
    </xsl:call-template>
  </xsl:template>

</xsl:stylesheet>

We now have a complete stylesheet that can be used as a library in other stylesheet. But we have not yet run the tests. Also you probably wonder what are this XML namespace test:tap and the template called tap:is.

test:tap is just a small XSLT test framework that I wrote and the report test results following the Test Anything Protocol that is well known by Perl programmers. tap:is is part of the test:tap API and just check for equality and reports in the TAP format.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:tap="test:tap"
  >

  <!-- Run all the tests in the test suite -->
  <xsl:template match="tap:suite">
    <xsl:message>1..<xsl:value-of select="count(node()[name()!=''])"/></xsl:message>
    <xsl:message># Suite: <xsl:value-of select="@name"/></xsl:message>
    <!-- TODO fix this expression -->
    <xsl:apply-templates select="node()[name()!='']"/>
  </xsl:template>

  <!-- Test Anything Protocol style reporting of tests -->
  <xsl:template name="tap:is">
    <xsl:param name="got"/>
    <xsl:param name="expected"/>
    <xsl:param name="name"/>
    <xsl:choose>
      <xsl:when test="$got = $expected">
        <xsl:message>ok <xsl:value-of select="position()"/> - <xsl:value-of select="concat($name, ' -&gt; ', $got)"/></xsl:message>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message>not ok <xsl:value-of select="position()"/> - <xsl:value-of select="$name"/></xsl:message>
        <xsl:message>#          got: <xsl:value-of select="$got"/></xsl:message>
        <xsl:message>#     expected: <xsl:value-of select="$expected"/></xsl:message>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

We now have two libraries. Let's add a bit more XSLT to glue them together. The main stylesheet applies tap:suite templates to all tap:suite from all imported stylesheets.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  >

  <!-- Test framework -->
  <xsl:import href="tap.xslt"/>

  <!-- All stylesheets to test -->
  <xsl:import href="date-time-Paris.xslt"/>

  <!-- Launch the tests embedded in libraires, whatever the input is -->
  <xsl:template match="/">
    <xsl:for-each select="document('')/xsl:transform/xsl:import/@href">
      <xsl:apply-templates select="document(.)//tap:suite" xmlns:tap="test:tap"/>
    </xsl:for-each>
  </xsl:template>

</xsl:transform>

We now have everything to run the test suite:

$ echo '<x/>' | xsltproc tap-run.xslt -
1..15
# Suite: date-time-Paris
ok 1 - 2008-09-24T21:37:52Z -> 2008-09-24T23:37:52+02:00
ok 2 - 2008-09-24T23:37:52Z -> 2008-09-25T01:37:52+02:00
not ok 3 - 2008-09-24T23:37:52.325Z
#          got: 2008-09-25T01:37:52.3249999999998+02:00
#     expected: 2008-09-25T01:37:52.325+02:00
ok 4 - 2008-10-01T00:00:00Z -> 2008-10-01T02:00:00+02:00
ok 5 - 2008-10-26T00:59:59Z -> 2008-10-26T02:59:59+02:00
ok 6 - 2008-10-26T01:00:00Z -> 2008-10-26T02:00:00+01:00
ok 7 - 2008-10-31T12:00:00Z -> 2008-10-31T13:00:00+01:00
ok 8 - 2008-11-24T21:37:52Z -> 2008-11-24T22:37:52+01:00
ok 9 - 2008-12-31T23:30:00Z -> 2009-01-01T00:30:00+01:00
ok 10 - 2009-01-01T00:00:00Z -> 2009-01-01T01:00:00+01:00
ok 11 - 2009-03-01T12:00:00Z -> 2009-03-01T13:00:00+01:00
ok 12 - 2009-03-29T00:59:59Z -> 2009-03-29T01:59:59+01:00
ok 13 - 2009-03-29T01:00:00Z -> 2009-03-29T03:00:00+02:00
ok 14 - 2009-03-30T12:00:00Z -> 2009-03-30T14:00:00+02:00
ok 15 - 2009-07-01T00:00:00Z -> 2009-07-01T02:00:00+02:00

So now I know that I have a failing test due to rounding occuring. For my XMLTV project it is not important as I will not have to handle decimal seconds.

lundi 11 février 2008

Les programmes télé de Télérama en XMLTV

XMLTV est un format informatique pour les programmes de télévision. Ce format est utilisable dans un nombre grandissant d'applications. Le magazine Télérama propose sur son site une grille des programmes télé, mais juste consultable sur le web. Pas de XMLTV.

Je vous propose donc de combler ce manque avec un petit cours de reverse engineering sur le web et la démonstration de quelques outils pour arriver rapidement à vos fins. La grille de Télérama est une excellente cible pour ce genre d'exercice parce que, vous le verrez, la tâche n'est pas simple, mais possible. Elle donne l'ocassion de montrer l'usage de plusieurs outils (curl, XSLT, Perl) et c'est un exemple de ma démarche de prototypage rapide en utilisant le meilleur de chacun.

MàJ 2008-02-15 : j'ai profondément remanié l'introduction et la conclusion suite à quelques commentaires de lecteurs.

Lire la suite...

samedi 3 novembre 2007

Une icône pour les liens vers Wikipédia

J'ai juste ajouté une petite touche à la feuille de style de ce blog (dont j'ai déjà longuement parlé en anglais) : une petite icône pour signaler les liens vers Wikipédia.

J'ai récupéré l'icône du site en ligne de commande avec Wget :

$ wget -O wikipedia.ico http://fr.wikipedia.org/favicon.ico
--19:23:35--  http://fr.wikipedia.org/favicon.ico
           => `wikipedia.ico'
Résolution de fr.wikipedia.org... 145.97.39.155
Connexion vers fr.wikipedia.org|145.97.39.155|:80... connecté.
requête HTTP transmise, en attente de la réponse... 200 OK
Longueur: 318 [image/x-icon]

100%[====================================>] 318           --.--K/s             

19:23:35 (30.79 MB/s) - « wikipedia.ico » sauvegardé [318/318]

Je l'ai ensuite convertie à la taille 14x14 au format GIF avec l'outil convert d'ImageMagick :

$ convert wikipedia.ico -resize 14x14 wikipedia.gif

L'image résultante faisait 595 octets. L'utilisation de l'application en ligne Image Optimizer m'a permis de réduire le nombre de couleurs de l'image à 16 et de réduire la taille à 167 octets.

En suivant Megan McDermott, j'ai modifié ma feuille de style pour ajouter la ligne suivante :

Il peut être utile parfois de désactiver ce style localement ou pour les blocs de code :

pre.code a:link, pre.terminal a:link,
.no-link-icon a:link,
a:link.no-icon
{ background: inherit; padding-right: inherit }

Mise à jour 2007-11-05 à 22:25 : mes règles pour les exceptions ne fonctionnent pas ! Je me suis fait avoir par les règles de précédence des règles CSS ! Il va falloir que je corrige cela...

Mise à jour 2007-11-05 à 22:46 : voici, j'espère, la correction. Il faut que j'augmente le poids des règles d'exception en augmentant le nombre d'attributs ou de pseudo-classes dans le sélecteur.

pre.code a:link[href], pre.terminal a:link[href],
.no-link-icon a:link[href],
a:link.no-icon[href]
{ background: inherit; padding-right: inherit }

lundi 3 septembre 2007

Paris Bluetooth MobiGuide : première réaction sur la forme

Je viens de découvrir ce soir que la Mairie de Paris a commencé une expérimentation de diffusion de contenu par Bluetooth à partir des stations Vélib’ : le Paris Bluetooth MobiGuide. Voici mes premières réactions, plutôt d'un point de vue technique (comme souvent ici), c'est à dire sur la forme plutôt que sur le fond et notamment du point de vue d'un utilisateur de Nokia N800.

Il y a quelques mois j'avais déjà reçu par Bluetooth une image JPEG de l'affiche du film Spiderman 3 en passant à coté d'un panneau d'affichage sur le boulevard Haussmann. J'ai repéré un panneau semblable du côté de la rue de la Gaîté. Dans le cas du MobiGuide, c'est potentiellement, pour le récepteur, une utilisation plus intéressante de la technologie Bluetooth.

Le MobiGuide est disponible de plusieurs façons :

  • pour consultation hors-ligne sur un téléphone mobile, sous la forme d'une application Java à installer après téléchargement :
    • par diffusion vers le téléphone mobile depuis des fontaines Bluetooth placées à des stations Vélib' ;
    • par téléchargement depuis en allant naviguer sur http://mobile.paris.fr/ ;
    • par téléchargement avec un ordinateur sur paris.fr ;
  • par consultation en ligne sur http://mobile.paris.fr/.

Ma première réaction : malgré la multiplicité des moyens d'accès, aucun ne me permet d'accéder facilement au MobiGuide avec les appareils dont je dispose :

  • L'application Java ne fonctionne que sur appareils mobiles, pas sur PC.
  • Le Nokia N800 est un appareil mobile qui dispose d'un chip Bluetooth, mais il n'a pas de machine virtuelle Java.
  • Mon téléphone mobile (Nokia 3100) n'a pas la capacité mémoire suffisante pour stocker l'application. 300 Ko, c'est trop pour lui !
  • Le site en ligne est inaccessible aux navigateurs web standards à cause d'un bête problème de configuration du serveur :
    C:\>curl -I http://www.v2asp.paris.fr/v2/mobile/bluetooth/site_PB1er/index.xhtml
    HTTP/1.1 200 OK
    Server: Microsoft-IIS/5.0
    Date: Sun, 02 Sep 2007 22:04:48 GMT
    Content-Type: application/octet-stream
    Accept-Ranges: bytes
    Last-Modified: Mon, 30 Jul 2007 14:25:45 GMT
    ETag: "20399984b5d2c71:86e"
    Content-Length: 1383
    Le Content-Type devrait être « application/xhtml+xml; charset=iso-8859-1 ». Ce simple paramètre bloque la consultation sur le N800 ou sur un PC (MSIE, Firefox) : au lieu de simplement montrer le fichier, le navigateur propose de le télécharger. Quant aux téléphones mobiles, le navigateur intégré de mon Nokia 3100 indique « Réponse inconnue », et Opera Mini signale « Opera Mini Basic ne supporte pas les téléchargements. Ignore "index.xhtml" avec le type "application/octet-stream". »

Je suis finalement arrivé (mais c'est laborieux) à accéder au contenu hors-ligne entièrement depuis mon N800 en bidouillant ainsi :

  1. téléchargement par wifi de Paris1.jar (j'aurais aussi pu aller me rendre à une fontaine Bluetooth pour récupérer le fichier, mais bon, j'habite pas à côté) ;
  2. renommage de Paris1.jar en Paris1.zip ;
  3. décompression de Paris1.zip dans le répertoire Paris1 ;
  4. lancement du navigateur web (l'extension .xhtml n'est pas reconnue directement depuis le Gestionnaire de fichiers) ;
  5. menu Page Web, Ouvrir fichier... pour ouvrir Paris1/microsite/index.xhtml ;
  6. ça y est ! J'accède au contenu XHTML.

Le résultat : j'obtiens un site qui ne prend même pas un quart de l'écran parce que la largeur est fixée en dur sur chaque page à 176 pixels (alors que l'écran du N800 fait 800 pixels). Et j'aboutis à des impasses telles que http://www.v2asp.paris.fr/v2/mobile/bluetooth/site_PB1er/622_ballades.xhtml où les liens pointent vers des fichiers texte qui sont probablement utilisés par l'application Java pour afficher des cartes, mais qui ne sont visibles ni dans le N800 ni sur le PC.

En résumé, c'est plutôt un fiasco. Faut que ça mûrisse encore pour être disponible sur un plus grand nombre de plateformes.

mardi 28 août 2007

TiddlyWiki and favicon

TiddlyWiki is a standalone wiki that is fully interactive and fully contained in a single HTML file. Here is a tip to add a favicon to your wiki.

To enable saving you have to give to the browser some special permissions allowing the JavaScript code to write to your disk. When using it with Microsoft Internet Explorer, the easy way to enable saving is to just rename your wiki as .hta to transform it into an "HTML Application", as Microsoft calls it.

But you can do better with HTML Applications than just decreasing the security level. I was particularly interested in a better integration with Windows. I wanted in particular to change the icon of the window that appears in the taskbar (I commonly have about 30-40 windows opened on my desktop). This is quite easy: you just have to add an <HTA:APPLICATION ICON="myfile.ico"> tag the <head> section of the HTML file.

Here is how to do it the TiddlyWiki way:

  1. Get an icon and save it as tiddlywiki.ico in the same directory as your wiki.hta file. For example: http://www.tiddlywiki.org/favicon.ico. You can also create you own icon here or here.
  2. Edit the built-in tiddler MarkupPreHead
  3. Insert the following text just after <!--{{{-->:
    <!--[if IE]>
    <HTA:APPLICATION ID="oHTA" APPLICATIONNAME="My wiki" ICON='tiddlywiki.ico'/>
    <![endif]-->
    <link rel='shortcut icon' href='tiddlywiki.ico' type='image/vnd.microsoft.icon '/>
    
  4. Reload your wiki.hta. That's it!

I now have to explore how to convert this to a plugin...

samedi 11 novembre 2006

DailyMotion's poor HTML code

For my post of this morning that included a video I did use DailyMotion services. When you upload a video, they provide HTML code to embed it on your site. OK, that seems fine. But it's not. Here is the code:

<div>
  <object width="425" height="335">
    <param name="movie" value="http://www.dailymotion.com/swf/2JarEXHqOuOxZ4psf"></param>
    <param name="allowfullscreen" value="true"></param>
    <embed src="http://www.dailymotion.com/swf/2JarEXHqOuOxZ4psf" type="application/x-shockwave-flash" width="425" height="334" allowfullscreen="true"></embed>
  </object><br />
  <b><a href="http://www.dailymotion.com/video/xmj2z_rallye-de-vence-2006-speciale-3-96">Rallye de Vence 2006 - Spéciale 3 - 96</a></b>
</div>

Here are my grievances:

  • This code uses <embed> tags, which have never been part of any W3C HTML specifications. <embed> is, AFAIK, a Netscape-only tag. Firefox/Mozilla now recognizes the standard <object> tag, so <embed> is only required for compatiblity with Netscape 4.x which, at web2.0 time, nobody uses anymore.
  • They do not provide alternative strictly validating XHTML code. Most blog and CMS software are now XHTML strict compliant. Embedding this code breaks strict validation and could cause the page to not display at all.
  • The code is not working with old Flash versions and does not tells why or proposes to upgrade. My parents have Flashplayer 6, and the display is weired. Even worse, when clicking on the link below the video to go to DailyMotion site, it crashes IE6 (with latest security patches).

So, here is my own code:

<div class="video dailymotion">
  <object width="425" height="335" classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0">
    <param name="movie" value="http://www.dailymotion.com/swf/2JarEXHqOuOxZ4psf"></param>
    <param name="FlashVars" value="playerMode=embedded"></param>
    <!--[if !IE]>-->
      <object width="425" height="335" data="http://www.dailymotion.com/swf/2JarEXHqOuOxZ4psf" type="application/x-shockwave-flash"></object>
    <!--<![endif]-->
  </object><br />
  <b><a href="http://www.dailymotion.com/video/xmj2z_rallye-de-vence-2006-speciale-3-96">Rallye de Vence 2006 - Spéciale 3 - 96</a></b>
</div>

Tested with Firefox 1.5.0.8 and Internet Explorer 6. I just hope it works with Opera/Safari/Konqueror…

Some reference documentation from Netscape/Mozilla and Ado be were useful.