I have made an actionscript that loads an external text file, and scrolls its content to the bottom:
var myTextLoader:URLLoader = new URLLoader();
myTextLoader.addEventListener(Event.COMPLETE, onLoaded);
function onLoaded(e:Event):void {
track_info.text = e.target.data;
addChild(track_info);
addEventListener(Event.ENTER_FRAME, scrollField);
}
function scrollField(e:Event):void {
if(track_info.scrollV < track_info.maxScrollV) {
track_info.scrollV++;
}else{
removeEventListener(Event.ENTER_FRAME, scrollField);
}
}
myTextLoader.load(new URLRequest("tracks.txt"));
The tracks.txt is a log file from a software that fetches the mp3 Artist and Song Name tags from a player in real time, in this format (it cannot be changed). The current song is at the bottom of the list. Each song starts with "[Day-Month-Year Hour:Min:Sec] * " (a 25 characters prefix):
[14-07-2010 20:21:33] Log file created for client.
[14-07-2010 20:21:33] Client connected.
[14-07-2010 20:26:21] * Artist 21 - Song 11
[14-07-2010 20:40:02] * Artist 42 - Song 02
[14-07-2010 20:45:04] * Artist 14 - Song 10
[14-07-2010 20:47:19] * Artist 46 - Song 04
[14-07-2010 20:51:09] * Artist 07 - Song 09
[14-07-2010 20:54:13] * Artist 54 - Song 01
[14-07-2010 20:57:32] * Artist 19 - Song 12
[14-07-2010 21:00:51] * Artist 35 - Song 06
[14-07-2010 21:04:02] * Artist 43 - Song 08
The script works, but I would like know if this issues can be solved:
I would like to show in the flash movie only the current song, the last line of the list (the one that is playing), not all the data in the tracks.txt file. Can it be done?
For that, the movie must to autoupdate the content from the .txt almost in real time to show the new song info into the textfield, replacing the previous one. Is there any way to do this?
Finally, is it possible to hide the "[Day-Month-Year Hour:Min:Sec] * " 25 characters prefix within the textfield, to show just the Artist - Song Name section in the flash movie?
Thank in advance for your help.
Edit
var reload:Timer = new Timer(5000, 0);
reload.addEventListener(TimerEvent.TIMER, onTimer);
function onTimer(event:TimerEvent):void{
var myTextLoader:URLLoader = new URLLoader();
myTextLoader.addEventListener(Event.COMPLETE, onLoaded);
function onLoaded(e:Event):void {
var lines:Array = e.target.data.split("\n");
var lastLine:String = lines[lines.length - 1];
var artistAndSong:String = lastLine.substr(24);
track_info.text = artistAndSong;
addChild(track_info);
myTextLoader.load(new URLRequest("tracks.txt"));
}
reload.start();
}
Edit
Maybe the split() doesn´t work with the real .log file. All the text is shown, not only the last line. This is the .log example:
[30-07-2010 03:21:34] Log file created for client "127.0.0.1,55684".
[30-07-2010 03:21:34] Client "127.0.0.1,55684" connected and has been identified as Traktor (or a something close enough).
[30-07-2010 03:22:58] * The Bravery - An Honest Mistake
[30-07-2010 03:23:22] * The Waterboys - The Whole of the Moon
Edit
var reload:Timer = new Timer(5000, 1);
reload.addEventListener(TimerEvent.TIMER, onTimer);
var tracksLoader:URLLoader = new URLLoader();
tracksLoader.addEventListene开发者_StackOverflow中文版r(Event.COMPLETE,onTracksLoaded);
tracksLoader.addEventListener(IOErrorEvent.IO_ERROR,onTracksError);
tracksLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onTracksError);
loadTracks();
function onTracksLoaded(e:Event):void {
trace("onTracksLoaded");
parseTracks(tracksLoader.data);
reload.start();
}
function onTimer(event:TimerEvent):void{
loadTracks();
}
function onTracksError(e:Event):void {
trace("onTracksError", e);
reload.start();
}
function loadTracks():void {
tracksLoader.load(new URLRequest("127.0.0.1,55684.log"));
}
function parseTracks(data:String):void {
try {
debugChars(data);
var lines:Array = data.split("\r\n");
var lastLine:String = lines[lines.length - 1];
var artistAndSong:String = lastLine.substr(24).split(" - ").join("\n");
trace(artistAndSong);
track_info.text = artistAndSong;
addChild(track_info);
} catch(e:Error) {
}
}
function debugChars(str:String):void {
var buffer:ByteArray = new ByteArray();
buffer.writeUTFBytes(str);
buffer.position = 0;
var result:String = "";
while(buffer.bytesAvailable) {
result += "0x" + uint(buffer.readUnsignedByte()).toString(16) + ", ";
if(buffer.position % 16 == 0) {
result += "\n";
}
}
// print this string...
trace(result);
}
Edit
Note that the line breaks between the 'Artist' and 'Song Name' are due to this code:
.split(" - ").join("\n");
The .log comes with 'Artist - Song Name', actually.
onTracksLoaded
0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32, 0x30, 0x31, 0x30, 0x20, 0x30, 0x33, 0x3a, 0x32,
0x31, 0x3a, 0x33, 0x34, 0x5d, 0x20, 0x4c, 0x6f, 0x67, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x63,
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x20, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2c, 0x35, 0x35, 0x36,
0x38, 0x34, 0x22, 0x2e, 0xa, 0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32, 0x30, 0x31, 0x30,
0x20, 0x30, 0x33, 0x3a, 0x32, 0x31, 0x3a, 0x33, 0x34, 0x5d, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x20, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2c, 0x35, 0x35, 0x36,
0x38, 0x34, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x61, 0x6e,
0x64, 0x20, 0x68, 0x61, 0x73, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x54, 0x72, 0x61, 0x6b, 0x74, 0x6f, 0x72,
0x20, 0x28, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67,
0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x20, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x29, 0x2e, 0xa,
0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32, 0x30, 0x31, 0x30, 0x20, 0x30, 0x33, 0x3a, 0x32,
0x32, 0x3a, 0x35, 0x38, 0x5d, 0x20, 0x2a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x42, 0x72, 0x61, 0x76,
0x65, 0x72, 0x79, 0x20, 0x2d, 0x20, 0x41, 0x6e, 0x20, 0x48, 0x6f, 0x6e, 0x65, 0x73, 0x74, 0x20,
0x4d, 0x69, 0x73, 0x74, 0x61, 0x6b, 0x65, 0xa, 0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32,
0x30, 0x31, 0x30, 0x20, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x3a, 0x32, 0x32, 0x5d, 0x20, 0x2a, 0x20,
0x54, 0x68, 0x65, 0x20, 0x57, 0x61, 0x74, 0x65, 0x72, 0x62, 0x6f, 0x79, 0x73, 0x20, 0x2d, 0x20,
0x54, 0x68, 0x65, 0x20, 0x57, 0x68, 0x6f, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65,
0x20, 0x4d, 0x6f, 0x6f, 0x6e, 0xa, 0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32, 0x30, 0x31,
0x30, 0x20, 0x30, 0x33, 0x3a, 0x32, 0x37, 0x3a, 0x35, 0x36, 0x5d, 0x20, 0x2a, 0x20, 0x42, 0x61,
0x62, 0x61, 0x73, 0x6f, 0x6e, 0x69, 0x63, 0x6f, 0x73, 0x20, 0x2d, 0x20, 0x59, 0x65, 0x67, 0x75,
0x61, 0xa,
g file created for client "127.0.0.1,55684".
[30-07-2010 03:21:34] Client "127.0.0.1,55684" connected and has been identified as Traktor (or a something close enough).
[30-07-2010 03:22:58] * The Bravery
An Honest Mistake
[30-07-2010 03:23:22] * The Waterboys
The Whole of the Moon
[30-07-2010 03:27:56] * Babasonicos
Yegua
For 1) and 3), String::split will do it.
It would be something like:
/*
\n is the end of line character. Depending on the program that creates
the text file, you might need to change it to \r\n or \r
Note I'm not doing any error checking, you might want to add it...
*/
var lines:Array = e.target.data.split("\n");
var lastLine:String = lines[lines.length - 1];
If the format is fixed, you can split the last line on "*" or even use substr to get the Artist and song name.
/*
Again, I'm not checking for any errors
*/
var songAndArtist:String = lastLine.split("*")[1];
or
var songAndArtist:String = lastLine.substr(25);
For 2), just poll the server at a reasonable interval. There are a couple of ways of doing this. One could be, whenever you load your file, start a Timer; when the this timer is done, stop the timer and reload the file. You could also use setTimeout instead of the timer.
Edit
Not sure what your problem was with the code you posted, but the part that parses the log works fine for me. I re-arrenged it a bit and added checks for errors during the loading of the data.
One problem with your code: you call your timer before waiting for you current load operation to finish. This could lead to problems. You don't need to have two downloads at the same time, so you are better of waiting for the download to complete (succesfully or not) before trying to reload (You might not want to try to reload on error; or maybe limit your retries to 2, 3 or something like that, but that's up to you).
Also, note I changed the timer's repeat count to 1, so you don't have to stop it. This means it will run once and then it will stop until you call start again). I structured a bit your code to separate its parts into different functions so it's easier to follow.
In the parseTracks function I wrapped all the code in a try/catch that catches almost all errors. This is kind of quick and dirty, so I'd generally not recommed that style of error handling, but might do the job here.
var reload:Timer = new Timer(5000, 1);
reload.addEventListener(TimerEvent.TIMER, onTimer);
var tracksLoader:URLLoader = new URLLoader();
tracksLoader.addEventListener(Event.COMPLETE,onTracksLoaded);
tracksLoader.addEventListener(IOErrorEvent.IO_ERROR,onTracksError);
tracksLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onTracksError);
loadTracks();
function onTracksLoaded(e:Event):void {
trace("onTracksLoaded");
parseTracks(tracksLoader.data);
reload.start();
}
function onTimer(event:TimerEvent):void{
loadTracks();
}
function onTracksError(e:Event):void {
trace("onTracksError", e);
reload.start();
}
function loadTracks():void {
tracksLoader.load(new URLRequest("tracks.txt"));
}
function parseTracks(data:String):void {
try {
var lines:Array = data.split("\n");
var lastLine:String = lines[lines.length - 1];
var artistAndSong:String = lastLine.substr(24);
trace(artistAndSong);
} catch(e:Error) {
}
}
Edit 2
Add this function and print its result to try to detect if there's some problem with the characters involved... Call it from parseTracks like this:
debugChars(data);
function debugChars(str:String):void {
var buffer:ByteArray = new ByteArray();
buffer.writeUTFBytes(str);
buffer.position = 0;
var result:String = "";
while(buffer.bytesAvailable) {
result += "0x" + uint(buffer.readUnsignedByte()).toString(16) + ", ";
if(buffer.position % 16 == 0) {
result += "\n";
}
}
// print this string...
trace(result);
}
instead of doing string split I would suggest a string match with some regular expressions
var $lastLine:String = String(e.target.data).match(/.*$/);
you can also get the last line minus anything in brackets [^]]*$
- but this might brake if the artist has a ]
in the name, but I would use the expression to get the artist from the $lastLine
anyway
then you can use
var $artistAndSong:String = $lastLine.match(/\*.*/);
this will match anything after(and including) the first *
if you play a bit more with regex, there's quite a bit you can get out of it, but always help to use something like http://regexpal.com/
精彩评论