Skip to main content

Topic: HOW TO: synchronise your last.fm playback stats with foobar (Read 269429 times) previous topic - next topic

0 Members and 1 Guest are viewing this topic.
  • carmenm
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #25
Last version works very well.
I have 2 question:
- can we create temporally tag with WSH Jscript? WOuld love to see if i loved a track when playing lastfm
- why wait 10sec before sync? why not half a second or even 1s?

Thanks

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #26
as for the 10 second rule, you're more than welcome to modify your own script. mine is staying as it is.

Code: [Select]
function on_playback_time(time) {
    if(t.eval() == 10) sync();
}


i suppose to show if a track is loved without writing tags, you could modify the button so it's "grey" when a track is unloved. then update it so it's red when a track is loved.

also new version of WSH panel mod is out. i strongly suggest everyone upgrades.

http://code.google.com/p/foo-wsh-panel-mod/downloads/list
  • Last Edit: 09 December, 2009, 05:33:54 AM by marc2003

  • carmenm
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #27
I am ok with you 10sec, i am just trying to understand it

For the greyed thing you are right that might the solution. i ll try that thanks.

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #28
one of the reasons i set 10 seconds is because i quite often start tracks then immediately change my mind and switch to something else. no need to spam the last.fm services for no reason. also, there are several last.fm components one might have installed at the same time. remember, they're probably all requesting data on playback start too. i'd just thought i'd leave a little breathing space.

as for the "grey" button idea, i might have a go at implementing this myself. then i'll disable the button if a track is already loved. after all, there is nothing else that can be done. you have to use the website to unlove a track.
  • Last Edit: 09 December, 2009, 09:17:43 AM by marc2003

  • carmenm
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #29
one of the reasons i set 10 seconds is because i quite often start tracks then immediately change my mind and switch to something else. no need to spam the last.fm services for no reason. also, there are several last.fm components one might have installed at the same time. remember, they're probably all requesting data on playback start too. i'd just thought i'd leave a little breathing space.

as for the "grey" button idea, i might have a go at implementing this myself. then i'll disable the button if a track is already loved. after all, there is nothing else that can be done. you have to use the website to unlove a track.

You are right about other lastfm components, that s one of the reason why i really think it would be great to merge all lastfm components.
Now for th grey button i implemented it. Works like a charm.
Code: [Select]
// ==PREPROCESSOR==

// @import "%fb2k_path%scriptstooltip_buttons.js"

// ==/PREPROCESSOR==



var username = "";

var api_key = "";



var sync_playcount = 1;

var playcount_tag_name = "LASTFM_PLAYCOUNT";

var sync_loved = 1;

var loved_tag_name = "LASTFM_LOVED";



var bw = 24;

var bh = 20;

var image_path = fb.FoobarPath + "images";



window.MinWidth = bw;

window.MinHeight = bh;



var g_metadb = fb.GetFocusItem();

var WshShell = new ActiveXObject("WScript.Shell");

var ok,length,n,h,func,tooltip;

var t = fb.TitleFormat("%playback_time_seconds%");

var lastfm_loved = 0;



on_metadb_changed();



function on_item_focus_change() {



if (g_metadb) window.UnwatchMetadb();

g_metadb = fb.IsPlaying ? fb.GetNowPlaying() : fb.GetFocusItem();

if (g_metadb) {

on_metadb_changed();

window.WatchMetadb(g_metadb);

}

}



function on_metadb_changed() {

if(!g_metadb) return;

length = fb.TitleFormat("%length_seconds%").EvalWithMetadb(g_metadb);

ok = false;

switch(true) {

case (username.length == 0):

case (api_key.length != 32):

n = image_path + "exclamation.png";

h = image_path + "exclamation_h.png";

tooltip = "Click to set your Last.fm username / api key.";

func = function() {window.ShowConfigure();}

break;

case (g_metadb.RawPath.indexOf("file://") == 0 && length > 30 && length < 10800 && g_metadb.Path.substring(g_metadb.Path.length - 3) != "cue"):

ok = true;

default:

  if (lastfm_loved  == 1)  {

  n = image_path + "love.png";

h = image_path + "love_h.png";

  }

  else {

  n = image_path + "unlove.png";

h = image_path + "unlove_h.png";

}



tooltip = fb.TitleFormat("Last.fm Love ''%title%'' by ''%artist%''").EvalWithMetadb(g_metadb);

func = function() {love_track(tooltip);}

}

Buttons = {

but: new Button(0,0,bw,bh, {normal: n, hover: h}, func, tooltip)

};

window.Repaint();

}



function on_playback_new_track() {

lastfm_loved = 0;

on_item_focus_change();

}



function on_playback_time(time) {

if(t.eval() == 1) sync();

}



function love_track(command) {

fb.RunContextCommandWithMetadb("Legacy commands (unsorted)/" + command,g_metadb);

sync();

}



function sync() {

if(sync_playcount == 0 && sync_loved == 0) return;

if(!ok){

fb.trace("Playcount sync: Cannot write tags to this file. Possible reasons- too long; too short; it's a stream; it references an external cue sheet.");

return;

}

var artist = fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb);

var track = fb.TitleFormat("%title%").EvalWithMetadb(g_metadb);

var url = "http://ws.audioscrobbler.com/2.0/?method=track.getinfo&api_key=" + api_key + "&username=" + username + "&artist=" + encodeURIComponent(artist) + "&track=" + encodeURIComponent(track);

fb.trace("Playcount sync: Contacting Last.fm....");

xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

xmlhttp.open("GET", url + "&s=" + Math.random(), true);

xmlhttp.setRequestHeader('User-Agent','foo_lastfm_playcount_sync');

xmlhttp.send();

xmlhttp.onreadystatechange = function() {

if (xmlhttp.readyState == 4) {

fb.trace("Status: " + xmlhttp.statustext);

if (xmlhttp.status == 200) {

//fb.trace(xmlhttp.responsetext);

var xmlDoc = xmlhttp.responseXML;

var y = xmlDoc.getElementsByTagName("userplaycount");

if(y.length == 1 && sync_playcount == 1) {

var lastfm_playcount = xmlDoc.getElementsByTagName("userplaycount")[0].childNodes[0].nodeValue;

var old_lastfm_playcount = fb.TitleFormat("%" + playcount_tag_name + "%").EvalWithMetadb(g_metadb);

if(lastfm_playcount != old_lastfm_playcount) {

fb.trace("Updating " + playcount_tag_name + " " + old_lastfm_playcount + " -> " + lastfm_playcount);

g_metadb.UpdateFileInfoSimple(playcount_tag_name, lastfm_playcount);

} else {

fb.trace(playcount_tag_name + " not updated. No changes found.");

}

}

var z = xmlDoc.getElementsByTagName("userloved");

if(z.length == 1 && sync_loved == 1) {

lastfm_loved = xmlDoc.getElementsByTagName("userloved")[0].childNodes[0].nodeValue;

if (lastfm_loved == 1) {

n = image_path + "love.png";

h = image_path + "love_h.png";

tooltip = fb.TitleFormat("Last.fm Love ''%title%'' by ''%artist%''").EvalWithMetadb(g_metadb);

func = function() {love_track(tooltip);}

Buttons = {

but: new Button(0,0,bw,bh, {normal: n, hover: h}, func, tooltip)

};

window.Repaint();

}

var old_lastfm_loved = fb.TitleFormat("%" + loved_tag_name + "%").EvalWithMetadb(g_metadb);

if((lastfm_loved == 1 && old_lastfm_loved == "?") || (lastfm_loved == 0 && old_lastfm_loved ==1)) {

fb.trace("Updating " + loved_tag_name + " " + old_lastfm_loved + " -> " + lastfm_loved);

g_metadb.UpdateFileInfoSimple(loved_tag_name, (lastfm_loved == 1) ? 1 : '');

} else {

fb.trace(loved_tag_name + " not updated. No changes found.");

}

}

} else {

fb.trace(xmlhttp.responsetext);

}

}

}

on_metadb_changed();

}



function on_mouse_rbtn_up(x, y) {

if(!g_metadb) return;

var MF_SEPARATOR = 0x00000800;

var MF_STRING = 0x00000000;

var MF_GRAYED = 0x00000001;



var _menu = window.CreatePopupMenu();

var idx;



_menu.AppendMenuItem(username.length > 0 ? MF_STRING : MF_GRAYED, 1, "Visit your Last.fm user profile page");

_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);

_menu.AppendMenuItem(MF_STRING, 2, "Configure...");



idx = _menu.TrackPopupMenu(x, y);



if (idx == 0) return;



switch(idx) {

case 1:

WshShell.run("http://www.last.fm/user/" + encodeURIComponent(username));

break;



case 2:

window.ShowConfigure();

}

return true;

}
  • Last Edit: 09 December, 2009, 09:24:26 AM by carmenm

  • T.P Wang
  • [*][*][*][*]
  • Developer
HOW TO: synchronise your last.fm playback stats with foobar
Reply #30
Just curious: Why not use on_item_played() callback ?

@carmenm:
Please remove your private data, and use:
Code: [Select]
[codebox][/codebox]
  • Last Edit: 09 December, 2009, 09:23:24 AM by T.P Wang

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #31
on_item_played doesn't work for tracks less than 60 seconds in length. instead it fires when the next track begins playback (and then again when that reaches 60 seconds as well. ). i've mentioned that twice in your thread now but no response so that's why i put in this workaround.

last.fm has a minimum length requirement of 30 seconds for scrobbling so it should be possible to update these these files.

@carmenm, i fail to see how that script works on streams. it's not possible. you haven't made the required changes.
  • Last Edit: 09 December, 2009, 10:10:17 AM by marc2003

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #32
i'm too late to edit my last post, so carmenm, do you want to try this test version?

http://cid-649d3bfeaf541fbb.skydrive.live..../guide/test.zip

new features-

-shows "loved" status of local files immediately by reading tags.
-disables love track feature when a track is already loved
-now checks lasfm for the loved status of streams and the changes the icon if it is
  • Last Edit: 09 December, 2009, 11:19:30 AM by marc2003

  • carmenm
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #33
i'm too late to edit my last post, so carmenm, do you want to try this test version?

http://cid-649d3bfeaf541fbb.skydrive.live..../guide/test.zip

new features-

-shows "loved" status of local files immediately by reading tags.
-disables love track feature when a track is already loved
-now checks lasfm for the loved status of streams and the changes the icon if it is
ok so your version works fine but personally i made a version with some code cleanup so that for example the code to update the button is only at one place
here it is if you want it. I am not sure why but still sometimes the button comes back toi grey. It seems that lastfm_loved goes back to 0. Not sure why yet
Code: [Select]
// ==PREPROCESSOR==
// @import "%fb2k_path%scripts\tooltip_buttons.js"
// ==/PREPROCESSOR==

var username = "";
var api_key = "";

var sync_playcount = 1;
var playcount_tag_name = "LASTFM_PLAYCOUNT";
var sync_loved = 1;
var loved_tag_name = "LASTFM_LOVED";

var bw = 24;
var bh = 20;
var image_path = fb.FoobarPath + "images\\";

window.MinWidth = bw;
window.MinHeight = bh;

var g_metadb = fb.GetFocusItem();
var WshShell = new ActiveXObject("WScript.Shell");
var ok,length,n,h,func,tooltip;
var t = fb.TitleFormat("%playback_time_seconds%");
var lastfm_loved = 0;
var cansync = 0;

on_metadb_changed();

function on_item_focus_change() {

if (g_metadb) window.UnwatchMetadb();
g_metadb = fb.IsPlaying ? fb.GetNowPlaying() : fb.GetFocusItem();
if (g_metadb) {
on_metadb_changed();
window.WatchMetadb(g_metadb);
}
}

function update_love_button(error) {
if (error == true) {
n = image_path + "exclamation.png";
h = image_path + "exclamation_h.png";
tooltip = "Click to set your Last.fm username / api key.";
func = function() {window.ShowConfigure();}
}
else
{
if (lastfm_loved  == 1)  {
n = image_path + "love.png";
h = image_path + "love_h.png";
tooltip = fb.TitleFormat("Last.fm  ''%title%'' by ''%artist%'' already loved!").EvalWithMetadb(g_metadb);
func = null;
}
else {
n = image_path + "unlove.png";
h = image_path + "unlove_h.png";
tooltip = fb.TitleFormat("Last.fm Love ''%title%'' by ''%artist%''").EvalWithMetadb(g_metadb);
func = function() {love_track(tooltip);}
}
}
}

function on_metadb_changed() {
if(!g_metadb) return;
length = fb.TitleFormat("%length_seconds%").EvalWithMetadb(g_metadb);
switch(true) {
case (username.length == 0):
case (api_key.length != 32):
udate_love_button(true);
break;
case (g_metadb.RawPath.indexOf("file://") == 0 && length > 30 && length < 10800 && g_metadb.Path.substring(g_metadb.Path.length - 3) != "cue"):
ok = true;
default:
update_love_button(false);
break;
}
Buttons = {
but: new Button(0,0,bw,bh, {normal: n, hover: h}, func, tooltip)
};
window.Repaint();
}

function on_playback_new_track() {
lastfm_loved = 0;
ok = false;
on_item_focus_change();
}

function on_playback_time(time) {
if(t.eval() == 10) sync();
}

function love_track(command) {
fb.RunContextCommandWithMetadb("Legacy commands (unsorted)/" + command,g_metadb);
sync();
}

function sync() {
if(sync_playcount == 0 && sync_loved == 0) return;
var artist = fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb);
var track = fb.TitleFormat("%title%").EvalWithMetadb(g_metadb);
var url = "http://ws.audioscrobbler.com/2.0/?method=track.getinfo&api_key=" + api_key + "&username=" + username + "&artist=" + encodeURIComponent(artist) + "&track=" + encodeURIComponent(track);
fb.trace("Playcount sync: Contacting Last.fm....");
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.open("GET", url + "&s=" + Math.random(), true);
xmlhttp.setRequestHeader('User-Agent','foo_lastfm_playcount_sync');
xmlhttp.send();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
fb.trace("Status: " + xmlhttp.statustext);
if (xmlhttp.status == 200) {
//fb.trace(xmlhttp.responsetext);
var xmlDoc = xmlhttp.responseXML;
var y = xmlDoc.getElementsByTagName("userplaycount");
if(ok == true && y.length == 1 && sync_playcount == 1) {
var lastfm_playcount = xmlDoc.getElementsByTagName("userplaycount")[0].childNodes[0].nodeValue;
var old_lastfm_playcount = fb.TitleFormat("%" + playcount_tag_name + "%").EvalWithMetadb(g_metadb);
if(lastfm_playcount != old_lastfm_playcount) {
fb.trace("Updating " + playcount_tag_name + " " + old_lastfm_playcount + " -> " + lastfm_playcount);
g_metadb.UpdateFileInfoSimple(playcount_tag_name, lastfm_playcount);
} else {
fb.trace(playcount_tag_name + " not updated. No changes found.");
}
}
var z = xmlDoc.getElementsByTagName("userloved");
if(z.length == 1 && sync_loved == 1) {
lastfm_loved = xmlDoc.getElementsByTagName("userloved")[0].childNodes[0].nodeValue;
var old_lastfm_loved = fb.TitleFormat("%" + loved_tag_name + "%").EvalWithMetadb(g_metadb);
if(ok ==true && ((lastfm_loved == 1 && old_lastfm_loved == "?") || (lastfm_loved == 0 && old_lastfm_loved ==1))) {
fb.trace("Updating " + loved_tag_name + " " + old_lastfm_loved + " -> " + lastfm_loved);
g_metadb.UpdateFileInfoSimple(loved_tag_name, (lastfm_loved == 1) ? 1 : '');
}
}
} else {
fb.trace(xmlhttp.responsetext);
}
}
}
on_metadb_changed();
}

function on_mouse_rbtn_up(x, y) {
if(!g_metadb) return;
var MF_SEPARATOR = 0x00000800;
var MF_STRING = 0x00000000;
var MF_GRAYED = 0x00000001;

var _menu = window.CreatePopupMenu();
var idx;

_menu.AppendMenuItem(username.length > 0 ? MF_STRING : MF_GRAYED, 1, "Visit your Last.fm user profile page");
_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
_menu.AppendMenuItem(MF_STRING, 2, "Configure...");

idx = _menu.TrackPopupMenu(x, y);

if (idx == 0) return;

switch(idx) {
case 1:
WshShell.run("http://www.last.fm/user/" + encodeURIComponent(username));
break;

case 2:
window.ShowConfigure();
}
return true;
}


  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #34
oh i know mine is an absolute mess with zillions of "IF" statements in it. that's why i put it up as a test version. i just wanted to make sure it worked first. i'll tidy it up later.

  • carmenm
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #35
Ok fine with me
by the way one question about global variables, what happens if the script is reloaded? I think that s my problem.
If i set a global var to 1, will it still be 1 after the script reloads?

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #36
using the editor dialog will reset any variable that are set during runtime (like loved status for a stream). under normal usage, this won't be an issue.

also, you're using on_metab_changed incorrectly. it gets called automatically when files are modified - so you're calling it twice with your sync function. and then for streams, it shouldn't be called at all because nothing has changed. you should just be updating the button.
  • Last Edit: 09 December, 2009, 01:08:19 PM by marc2003

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #37
yet another new version uploaded. added features from earlier tests.

Quote
09/12/2009
-   Button now shows the “loved” status of tracks and streams.
-   If a track is “loved”, the button is disabled.


link

  • TsukasaX
  • [*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #38
Any good way to put the information collected into a database instead of writing tags? I'm playing music from my NAS and tag writing is usually slow (interrupts playback) and takes two updates to actually update.

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #39
i did experiment with a component called foo_customdb. this uses an sqlite database and i did manage to use WSH panel mod to update it via a command line tool. unfortunately, the command window flicker drove me round the bend. i couldn't live with it so i gave up.

another user has been trying to tackle this by editing the database directly from javascript and an sqlite dll but he's getting random database locked errors. also the files he's using isn't compatible with windows 7 64bit so i couldn't try it. you might want to skim through the last page of this thread.

http://www.hydrogenaudio.org/forums/index....0363&st=425

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #40
right, here's my latest experiment -  a new version which DOES NOT write file tags. instead it uses text files to store the data. however, this does require the usage of ELplaylist to display it. i've included a sample .elp file that can be imported. but if you already use ELPlaylist, i've included instructions on how to use it in your own config.

screenshot:


it can now store playcount/loved status for absolutely anything -streams/cue files included.
  • Last Edit: 10 December, 2009, 05:40:32 AM by marc2003

  • TsukasaX
  • [*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #41
Unfortunately I use NG Playlist instead of  ELplaylist; I'll have to see if it takes much to switch.

Judging by your post on the sqlite, that sounds a little excessive for this project unfortunately.

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #42
new experimental ELplaylist version uploaded. this only writes one file per track instead of 2. in the unlikely event anyone tried my earlier version, it's now to safe to delete all the .txt files in your "lastfm_stats" folder. (should free up some valuable space.  )

click me
  • Last Edit: 10 December, 2009, 12:26:39 PM by marc2003

HOW TO: synchronise your last.fm playback stats with foobar
Reply #43
marc, How would I edit your script in order for it to check/update the track... let's say.... 10 seconds before the song is ended (in addition to 10 seconds after it starts)? In a lot of cases, I'll love a track during playback, not beforehand... Also, this way it would typically update tracks according to that you've actually just played through them?

Is it even possible to have two points of checking in a given song?

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #44
Code: [Select]
In a lot of cases, I'll love a track during playback, not beforehand...


well of course. from the readme.... 

Quote
Usage scenarios:

-   A track starts playing and you do nothing. It will automatically contact last.fm to fetch your playback statistics/loved track status when the playback time hits 10 seconds. Depending on the result and file type, your file will then be tagged with the response.

-   You click the “love” button. This will run foo_softplaylists and then automatically contact last.fm as above. This should now show the loved status immediately in your file. If the “love” action fails at the server end, your file will not be tagged by this script. Tags are only updated based on data retrieved from last.fm.


there's no point in checking near the end because a scrobble isn't counted until playback stops.

HOW TO: synchronise your last.fm playback stats with foobar
Reply #45
Code: [Select]
In a lot of cases, I'll love a track during playback, not beforehand...


well of course. from the readme.... 

Quote
Usage scenarios:

-   A track starts playing and you do nothing. It will automatically contact last.fm to fetch your playback statistics/loved track status when the playback time hits 10 seconds. Depending on the result and file type, your file will then be tagged with the response.

-   You click the “love” button. This will run foo_softplaylists and then automatically contact last.fm as above. This should now show the loved status immediately in your file. If the “love” action fails at the server end, your file will not be tagged by this script. Tags are only updated based on data retrieved from last.fm.


there's no point in checking near the end because a scrobble isn't counted until playback stops.


Ah... Right on on boths points.

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #46
new experimental ELplaylist version uploaded. this only writes one file per track instead of 2.


anybody who tried this should revert to v1. download (existing stats will stay and work fine)

it's fine now but slows down with the more records you have. i tested 10,000 dummy files and found there was a second or so delay. and i even tried 100,000. and that resulted in a 2-3 second delay when switching tracks. totally unacceptable.

v1 is fine however.

  • carmenm
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #47
Hi marc, i have a question, could you share your CUI config?, i love your toolbar at the top and the bottom and would love to do something like that.

Thanks

  • marc2003
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #48
here you go. just import.fcl and play around. i can't be bothered to write any instructions.

http://cid-649d3bfeaf541fbb.skydrive.live....ide/Archive.zip

experimental ELplaylist version removed as i'm working on a new version which isn't backwards compatible with it.

new main version uploaded

Quote
Added auto-love feature. Turned off by default but you can enable it to automatically love tracks as they are played based on your own custom title formatting. eg $ifequal(%rating%,5,1,0)
  • Last Edit: 11 December, 2009, 10:33:58 AM by marc2003

  • carmenm
  • [*][*][*][*][*]
HOW TO: synchronise your last.fm playback stats with foobar
Reply #49
here you go. just import.fcl and play around. i can't be bothered to write any instructions.

http://cid-649d3bfeaf541fbb.skydrive.live....ide/Archive.zip

experimental ELplaylist version removed as i'm working on a new version which isn't backwards compatible with it.

new main version uploaded

Quote
Added auto-love feature. Turned off by default but you can enable it to automatically love tracks as they are played based on your own custom title formatting. eg $ifequal(%rating%,5,1,0)



The only thing that comes to my mind "WOW"!

Thanks