package lastfmvis { import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.TimerEvent; import flash.net.URLLoader; import flash.net.URLRequest; import flash.utils.Timer; public class LastfmXMLLoader { private var SERVICE_URL:String = "http://ws.audioscrobbler.com/2.0/?method="; private var NUM_REQUESTS:Number = 7; private var api_key:String; private var _onComplete:Function; private var _onProgress:Function; private var _onError:Function; private var _collectedXML:Array; private var progressCounter:Number = 0; private var totalRequests:Number = 0; private var collectedXMLData:Array = []; public function LastfmXMLLoader(apiKey:String) { api_key = apiKey; } public function retrieveWeeklyArtistListenData(username:String, weeks:Array):void { if (weeks.length == 0) _onComplete(null); // Limit to five requests/second var timer:Timer = new Timer(1000); totalRequests = weeks.length; timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void { for (var i:Number = 0; i < NUM_REQUESTS; i++) { if (weeks.length == 0) { timer.stop(); return; } var week:Array = weeks.pop(); getArtistsForWeek(username, week[0], week[1]); } }); timer.start(); } public function retrieveWeeklyTrackListenData(username:String, weeks:Array):void { // Limit to five requests/second var timer:Timer = new Timer(1000); totalRequests = weeks.length; timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void { for (var i:Number = 0; i < NUM_REQUESTS; i++) { if (weeks.length == 0) { timer.stop(); return; } var week:Array = weeks.pop(); getTracksForWeek(username, week[0], week[1]); } }); timer.start(); } public function retrieveTagsForArtists(artists:Array):void { // Limit to five requests/second var timer:Timer = new Timer(1000); totalRequests = artists.length; timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void { for (var i:Number = 0; i < NUM_REQUESTS; i++) { if (artists.length == 0) { timer.stop(); return; } var artist:String = artists.pop(); getTagsForArtist(artist); } }); timer.start(); } public function retrieveAvailableWeeks(username:String):void { var request:URLRequest = new URLRequest(SERVICE_URL + "user.getweeklychartlist&user=" + username + "&api_key=" + api_key); var weekLoader:URLLoader = new URLLoader(); weekLoader.addEventListener(Event.COMPLETE, function(e:Event):void { var weeksXML:XML = parseXML(weekLoader); if (weeksXML == null) _onError(); else _onComplete([weeksXML]); }); weekLoader.load(request); weekLoader.addEventListener(IOErrorEvent.IO_ERROR, function(e:Event):void { _onError(e); }); } public function set onComplete(func:Function):void { _onComplete = func; } public function set onError(func:Function):void { _onError = func; } public function set onProgress(func:Function):void { _onProgress = func; } private function getArtistsForWeek(username:String, start:Number, end:Number):void { var request:URLRequest = new URLRequest(SERVICE_URL + "user.getweeklyartistchart&user=" + username + "&api_key=" + api_key + "&from=" + start + "&to=" + end); var weekOfSongsLoader:URLLoader = new URLLoader(); var retries:Number = 3; try { weekOfSongsLoader.load(request); } catch (error:SecurityError) { trace("Audioscrobbler security error"); trace(error.message); } // Each week being complete means one progress step for all weeks weekOfSongsLoader.addEventListener(Event.COMPLETE, function(e:Event):void { xmlItemReceived(weekOfSongsLoader); }); weekOfSongsLoader.addEventListener(flash.events.IOErrorEvent.IO_ERROR, function(e:Event):void { if (retries > 0) { retries--; weekOfSongsLoader.load(request); } else { throw new Error("Cannot load URL: " + request.url + "\n Please refresh the page and try again"); } }); } private function getTracksForWeek(username:String, start:Number, end:Number):void { var request:URLRequest = new URLRequest(SERVICE_URL + "user.getweeklytrackchart&user=" + username + "&api_key=" + api_key + "&from=" + start + "&to=" + end); var weekOfSongsLoader:URLLoader = new URLLoader(); var retries:Number = 3; try { weekOfSongsLoader.load(request); } catch (error:SecurityError) { trace("Audioscrobbler security error"); trace(error.message); } // Each week being complete means one progress step for all weeks weekOfSongsLoader.addEventListener(Event.COMPLETE, function(e:Event):void { xmlItemReceived(weekOfSongsLoader); }); weekOfSongsLoader.addEventListener(flash.events.IOErrorEvent.IO_ERROR, function(e:Event):void { if (retries > 0) { retries--; weekOfSongsLoader.load(request); } else { throw new Error("Cannot load URL: " + request.url + "\n Please refresh the page and try again"); } }); } /** * Finds out the first tag for each artist listened to */ private function getTagsForArtist(artist:String):void { // Try 3 retries in event of IOError var retries:Number = 3; var tagLoader:URLLoader = new URLLoader(); var request:URLRequest = new URLRequest(SERVICE_URL + "artist.gettoptags&artist=" + encodeURIComponent(artist) + "&api_key=" + api_key); try { tagLoader.load(request); } catch (error:SecurityError) { trace("Audioscrobbler security error"); trace(error.message); } tagLoader.addEventListener(Event.COMPLETE, function(e:Event):void { xmlItemReceived(tagLoader); }); tagLoader.addEventListener(flash.events.IOErrorEvent.IO_ERROR, function(e:Event):void { if (retries > 0) { retries--; tagLoader.load(request); } else { throw new Error("Cannot load URL: " + request.url + "\n Please refresh the page and try again"); } }); } private function parseXML(loader:URLLoader):XML { var outXML:XML; try { outXML = new XML(loader.data); } catch (e: TypeError) { trace("XML parsing error"); trace(e.message); return null; } if (outXML.@status != "ok") { trace("Last.fm protocol error"); return null; } return outXML; } private function xmlItemReceived(data:URLLoader):void { var listenData:XML = parseXML(data); progressCounter++; collectedXMLData.push(listenData); _onProgress(progressCounter, totalRequests); if (progressCounter == totalRequests) { progressCounter = 0; _onComplete(collectedXMLData); } } } }