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.
// ==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;
}