Gestern Abend lieferte ich mir einen Wettstreit mit Kollege Burgdorfer – wer springt als erstes auf den AJAX-Zug (oder doch eher: -Hype?) auf und baut die erste AJAX-Anwendung? Nun, ich habe gewonnen – jedenfalls mit Blick auf die Geschwindigkeit der Umsetzung. Er habe aber eine Idee in Petto, die ihn zum Millionär machen werde. Deren Umsetzung ist für diese Wochenende geplant. Mal schauen, ob er bald in die Liga von Larry Page und Sergey Brin aufsteigen wird. Ich wünsche ihm jedenfalls viel Erfolg auf dem Weg zur ersten (mit AJAX generierten) Million.
Anwendung
Doch wo findet sich nun AJAX auf eMeidi.com? Es ist die Jukebox. Diese updated sich nun alle 15’000 Millisekunden und zeigt somit immer relativ akkurat auf, welche Musik bei mir in iTunes gerade läuft. Die Information gelangt mittels einem AppleScript auf meinen Server: Das AppleScript liest den aktuellen Track aus iTunes aus und übermittelt dessen Angaben via GET an ein PHP-Script auf meinem Server. Das PHP-Script generiert aus den GET-Variablen eine simple Text-Datei, die HTML-Code enthält. AJAX macht schliesslich nichts anderes, als diese Text-Datei zu inkludieren. Wieso AJAX? Weil die Benutzer dann meine Homepage nicht jede Minute manuell nachladen müssen, um einen Songwechsel zu bemerken. Ab sofort geht das nämlich vollautomatisch.
Zugegeben: Nichts bahnbrechendes. Aber es geht ja primär darum, mit neuen Techniken in Kontakt zu kommen. Man lehrt ja gerade in unserem Business nie aus …
Umsetzung
AppleScript
Als Erstes mal den AppleScript-Code:
on idle set strServer to "http://www.domain.com/tracker.php" set strTitle to "" set strArtist to "" set strAlbum to "" set intIsRunning to 0 set intIsPlaying to 0 try tell application "System Events" --no more using the finder if (get name of every process) contains "iTunes" then set intIsRunning to 1 end if end tell if intIsRunning = 1 then tell application "iTunes" --start talking to iTunes try if player state is playing then --now we want to see if iTunes is even playing set intIsPlaying to 1 if exists (address of current track) then --it's an internet stream else set strTitle to the name of the current track set strArtist to the artist of the current track set strAlbum to the album of the current track end if end if end try end tell end if end try set strURL to strServer & "?playing=" & intIsPlaying & "&artist=" & urlencode(strArtist, true, true) & "&album=" & urlencode(strAlbum, true, true) & "&title=" & urlencode(strTitle, true, true) set shellCommand to "/usr/bin/curl \"" & strURL & "\"" do shell script shellCommand return 15 end idle on urlencode(this_text, encode_URL_A, encode_URL_B) set the standard_characters to ¬ "abcdefghijklmnopqrstuvwxyz0123456789" set the URL_A_chars to "$+!'/?;&@=#%><{}[]\"~`^\\|*" set the URL_B_chars to ".-_:" set the acceptable_characters to the standard_characters if encode_URL_A is false then ¬ set the acceptable_characters to ¬ the acceptable_characters & the URL_A_chars if encode_URL_B is false then ¬ set the acceptable_characters to ¬ the acceptable_characters & the URL_B_chars set the encoded_text to "" repeat with this_char in this_text if this_char is in the acceptable_characters then set the encoded_text to ¬ (the encoded_text & this_char) else set the encoded_text to ¬ (the encoded_text & encode_char(this_char)) as string end if end repeat return the encoded_text end urlencode on encode_char(this_char) set the ASCII_num to (the ASCII number this_char) set the hex_list to ¬ {"0", "1", "2", "3", "4", "5", "6", "7", "8", ¬ "9", "A", "B", "C", "D", "E", "F"} set x to item ((ASCII_num div 16) + 1) of the hex_list set y to item ((ASCII_num mod 16) + 1) of the hex_list return ("%" & x & y) as string end encode_char
Download: getsonginfo-clean.scpt
ACHTUNG: Einzelne Bausteine habe ich aus dem Netz zusammengeklaubt. Dank gebührt all denen, die etwas an das Scriptlein beigesteuert haben.
Wichtig ist zum einen strServer (PHP-Script auf dem Server) und return 15 (Wartedauer in Sekunden, bis die Infos erneut abgefragt und übermittelt werden).
Prototype
Natürlich hätte ich die JavaScript-Library von Grund auf neu programmieren können, die AJAX und andere nützliche Hilfsmittel zur Verfügung stellt, um Web 2.0-Anwendungen zu realisieren. Ich habe dann der Einfachheit halber doch auf das JavaScript-Framework Prototype zurückgegriffen - insbesondere die Cross-Browser-Kompatibilität ist hier exzellent umgesetzt, weshalb man sich darüber kaum mehr Gedanken machen muss.
HTML/JavaScript
Prototype wird normal in index.html eingebunden:
<script language="javascript" src="/inc/prototype.js" type="text/javascript"></script>
Der Übersichtlichkeit halber habe ich dann meinen eigenen Code in ein separates JavaScript-Include ausgelagert. Dank Prototype reicht ein Sechszeiler aus, um die Rotation zum Laufen zu bringen:
function updatePlaylist() { var strElement = 'playlist'; new Ajax.Updater( {success: strElement}, 'subdomains/dev/itunes.txt', {asynchronous: true} ); window.setTimeout("updatePlaylist()",15000); return true; }
Es gäbe auch ein Objekt Ajax.PeriodicalUpdater, aber leider fand ich im Netz gerade nirgends eine aufschlussreiche Beschreibung, weshalb ich auf das gute, alte setTimeout zurückgegriffen habe. Klappt auch damit wunderbar.
Fallstricke
Obwohl das Endresultat mit sechs Zeilen simpel daherkommt, habe ich mir daran doch etwa eine Stunde die Zähne ausgebissen. Leider verfügt Prototype über keine sehr guten Debugging-Features (oder ich habe diese schlicht nicht entdeckt). Rückblickend vermute ich eine falsch formulierte URL (http://...). Als ich die URL relativ angegeben habe, funktionierte alles plötzlich wie geschmiert.
Nachtrag: Ich habe jetzt herausgefunden, wieso es mit der URL nicht geklappt hat - ich habe mit einer Seite auf www.eMeidi.com auf dev.eMeidi.com zugreifen wollen. Das geht anscheinend nicht:
Can't access domains other than the calling domain
Quelle: AJAX Presentation Outline.
Als Nachschlagewerk empfehle ich script.aculo.us sowie AJAX Tutorial with Prototype - .cfm lebt noch? Egal, Pete hat eine sehr simple, aber bemerkenswert handliche PLZ-Nachschlagefunktion mit AJAX generiert.