function LastFM(user) { var lastfm_api_key = "15f7532dff0b8d84635c757f9f18aaa3"; var lastfm_secret="3ddf4cb9937e015ca4f30296a918a2b0"; var logged_in = false; var username = user; var token = ""; var self=this; var queue = new Array(); var throttle = null; var throttleTime = 500; var backofftimer; function startlogin() { self.login($('#configpanel input[name="lfmuser"]').val()); } function logout() { prefs.save({lastfm_session_key: ''}); logged_in = false; uiLoginBind(); } function uiLoginBind() { if (!logged_in) { $('.lastfmlogin-required').removeClass('notenabled').addClass('notenabled'); $('#lastfmloginbutton').off('click').on('click', startlogin).html(language.gettext('config_loginbutton')); } else { $('.lastfmlogin-required').removeClass('notenabled'); $('#lastfmloginbutton').off('click').on('click', logout).html(language.gettext('button_logout')); } } if (prefs.lastfm_session_key !== "" || typeof lastfm_session_key !== 'undefined') { logged_in = true; } uiLoginBind(); function speedBackUp() { throttleTime = 500; } function setThrottling(t) { clearTimeout(backofftimer); throttleTime = t; backofftimer = setTimeout(speedBackUp, 90000); } this.showloveban = function(flag) { if (logged_in && flag) { $("#lastfm").show(); } else { $("#lastfm").hide(); } } this.isLoggedIn = function() { return logged_in; } this.getLanguage = function() { switch (prefs.lastfmlang) { case "default": return null; break; case "interface": return interfaceLanguage; break; case "browser": return browserLanguage; break; case "user": if (prefs.user_lang != "") { return prefs.user_lang; } else { return null; } break; } } this.username = function() { return username; } this.login = function (user, pass) { username = user; var options = {api_key: lastfm_api_key, method: "auth.getToken"}; var keys = getKeys(options); var it = ""; for(var key in keys) { it = it+keys[key]+options[keys[key]]; } it = it+lastfm_secret; options.api_sig = hex_md5(it); options.format = 'json'; var url = "https://ws.audioscrobbler.com/2.0/"; var adder = "?"; var keys = getKeys(options); for(var key in keys) { url=url+adder+keys[key]+"="+options[keys[key]]; adder = "&"; } $.get(url, function(data) { token = data.token; debug.log("LASTFM","Token",token); var lfmlog = new popup({ css: { width: 600, height: 400 }, fitheight: true, title: language.gettext("lastfm_loginwindow") }); var mywin = lfmlog.create(); mywin.append('
");
bio = bio.replace(/($2');
return bio.fixDodgyLinks();
} else {
return "";
}
}
function LastFMGetRequest(options, cache, success, fail, reqid) {
options.format = "json";
options.cache = cache;
queue.push({url: options, success: success, fail: fail, flag: false, cache: cache, reqid: reqid, retries: 0});
if (throttle == null && queue.length == 1) {
lastfm.getRequest();
}
}
function addGetOptions(options, method) {
options.api_key = lastfm_api_key;
options.autocorrect = prefs.lastfm_autocorrect ? 1 : 0;
options.method = method;
}
var getKeys = function(obj) {
var keys = [];
for(var key in obj){
keys.push(key);
}
keys.sort();
return keys;
}
this.getRequest = function() {
var req = queue[0];
clearTimeout(throttle);
if (req) {
if (req.flag) {
debug.trace("LASTFM","Request pulled from queue is already being handled!")
return;
}
queue[0].flag = true;
debug.trace("LASTFM","Taking next request from queue",req.url);
if (req.url == "POST") {
debug.log("LASTFM", "Handling POST request via queue");
$.ajax({
method: "POST",
url: "https://ws.audioscrobbler.com/2.0/",
data: req.options,
dataType: 'json',
timeout: 5000
})
.done(function(data) {
throttle = setTimeout(lastfm.getRequest, throttleTime);
req = queue.shift();
debug.log("LASTFM", req.options.method,"request success");
if (data.error) {
debug.blurt("LASTFM","Last FM signed request failed with status",data.error.message);
req.fail(data);
} else {
req.success(data);
}
})
.fail(function(xhr,status,err) {
req = queue.shift();
debug.error("LASTFM",req.options.method,"request error",status,err);
if (xhr.responseJSON) {
var errorcode = xhr.responseJSON.error;
var errortext = xhr.responseJSON.message;
debug.error("LASTFM", 'Error Code',errorcode,"Message",errortext);
switch (errorcode) {
case 4:
case 9:
case 10:
case 14:
case 26:
debug.error("LASTFM","We are not authenticated. Logging Out");
logout();
req.fail(null);
break;
case 29:
debug.warn("LASTFM","Rate Limit Exceeded. Slowing Down");
setThrottling(throttleTime*2);
// Fall through
default:
if (req.retries < 3) {
debug.log("LASTFM","Retrying...");
req.retries++;
req.flag = false;
queue.unshift(req);
} else {
req.fail(null);
}
}
}
throttle = setTimeout(lastfm.getRequest, throttleTime);
});
} else {
var getit = $.ajax({
method: 'POST',
url: 'browser/backends/getlfmdata.php',
data: req.url,
dataType: 'json'
})
.done(function(data) {
var c = getit.getResponseHeader('Pragma');
debug.debug("LASTFM","Request success",c,data);
if (c == "From Cache") {
throttle = setTimeout(lastfm.getRequest, 100);
} else {
throttle = setTimeout(lastfm.getRequest, throttleTime);
}
req = queue.shift();
debug.debug("LASTFM","Calling success callback");
if (req.reqid || req.reqid === 0) {
req.success(data, req.reqid);
} else {
req.success(data);
}
})
.fail(function(xhr,status,err) {
throttle = setTimeout(lastfm.getRequest, throttleTime);
req = queue.shift();
debug.warn("LASTFM", "Get Request Failed",xhr,status,err);
var errormessage = language.gettext('lastfm_error');
if (xhr.responseJSON) {
var errorcode = xhr.responseJSON.error;
var errortext = xhr.responseJSON.message;
errormessage += '
'+errortext;
if (errorcode == 29) {
debug.warn("LASTFM","Rate Limit Exceeded. Slowing Down");
setThrottling(throttleTime*2);
}
} else {
errormessage += ' ('+xhr.status+' '+err+')';
}
if (req.reqid || req.reqid === 0) {
req.fail(null, req.reqid);
} else {
req.fail({error: 1, message: errormessage});
}
});
}
} else {
throttle = null;
}
}
function LastFMSignedRequest(options, success, fail) {
// We've passed an object but we need the properties to be in alphabetical order
var keys = getKeys(options);
var it = "";
for(var key in keys) {
if (keys[key] != 'format' && keys[key] != 'callback') {
it = it+keys[key]+options[keys[key]];
}
}
it = it+lastfm_secret;
options.api_sig = hex_md5(it);
queue.push({
url: "POST",
options: options,
success: success,
fail: fail,
flag: false,
retries : 0
});
if (throttle == null && queue.length == 1) {
lastfm.getRequest();
}
}
function addSetOptions(options, method) {
options.format = 'json';
options.api_key = lastfm_api_key;
options.sk = prefs.lastfm_session_key;
options.method = method;
}
this.track = {
love : function(options,callback) {
if (logged_in) {
addSetOptions(options, "track.love");
LastFMSignedRequest(
options,
function() {
infobar.notify(language.gettext("label_loved")+" "+options.track);
callback(true);
},
function() {
infobar.error(language.gettext("label_lovefailed"));
}
);
}
},
unlove : function(options,callback,callback2) {
if (logged_in) {
addSetOptions(options, "track.unlove");
LastFMSignedRequest(
options,
function() {
infobar.notify(language.gettext("label_unloved")+" "+options.track);
callback(false);
},
function() {
infobar.error(language.gettext("label_unlovefailed"));
}
);
}
},
getInfo : function(options, callback, failcallback, reqid) {
// If we're logged in to Last.FM we don't use the cache for this request
// because it contains 'userloved', which we might update
if (username != "") { options.username = username; }
addGetOptions(options, "track.getInfo");
if (self.getLanguage()) {
options.lang = self.getLanguage();
}
LastFMGetRequest(
options,
!logged_in,
callback,
failcallback,
reqid
);
},
getTags: function(options, callback, failcallback, reqid) {
if (username != "") { options.user = username; }
addGetOptions(options, "track.getTags");
LastFMGetRequest(
options,
!logged_in,
callback,
failcallback,
reqid
);
},
getSimilar: function(options, callback, failcallback) {
addGetOptions(options, "track.getSimilar");
LastFMGetRequest(
options,
true,
callback,
failcallback
);
},
addTags : function(options, callback, failcallback) {
if (logged_in) {
addSetOptions(options, "track.addTags");
LastFMSignedRequest(
options,
function() { callback("track", options.tags) },
function() { failcallback("track", options.tags) }
);
}
},
removeTag: function(options, callback, failcallback) {
if (logged_in) {
addSetOptions(options, "track.removeTag");
LastFMSignedRequest(
options,
function() { callback("track", options.tag); },
function() { failcallback("track", options.tag); }
);
}
},
updateNowPlaying : function(options) {
if (logged_in && prefs.lastfm_scrobbling) {
addSetOptions(options, "track.updateNowPlaying");
LastFMSignedRequest(
options,
function() { },
function() { debug.warn("LAST FM","Failed to update Now Playing",options) }
);
}
},
scrobble : function(options) {
if (logged_in && prefs.lastfm_scrobbling) {
debug.log("LAST FM","Last.FM is scrobbling");
addSetOptions(options, "track.scrobble");
LastFMSignedRequest(
options,
function() { },
function() { infobar.error(language.gettext("label_scrobblefailed")+" "+options.track) }
);
}
},
}
this.album = {
getInfo: function(options, callback, failcallback) {
addGetOptions(options, "album.getInfo");
if (username != "") { options.username = username }
options.autocorrect = prefs.lastfm_autocorrect ? 1 : 0;
if (self.getLanguage()) {
options.lang = self.getLanguage();
}
debug.mark("LASTFM","album.getInfo",options);
LastFMGetRequest(
options,
true,
callback,
failcallback
);
},
getTags: function(options, callback, failcallback) {
addGetOptions(options, "album.getTags");
if (username != "") { options.user = username }
debug.mark("LASTFM","album.getTags",options);
LastFMGetRequest(
options,
!logged_in,
callback,
failcallback
);
},
addTags : function(options, callback, failcallback) {
if (logged_in) {
addSetOptions(options, "album.addTags");
LastFMSignedRequest(
options,
function() { callback("album", options.tags) },
function() { failcallback("album", options.tags) }
);
}
},
removeTag: function(options, callback, failcallback) {
if (logged_in) {
addSetOptions(options, "album.removeTag");
LastFMSignedRequest(
options,
function() { callback("album", options.tag); },
function() { failcallback("album", options.tag); }
);
}
}
}
this.artist = {
getInfo: function(options, callback, failcallback, reqid) {
addGetOptions(options, "artist.getInfo");
if (username != "") { options.username = username }
if (self.getLanguage()) {
options.lang = self.getLanguage();
}
LastFMGetRequest(
options,
true,
callback,
failcallback,
reqid
);
},
getTags: function(options, callback, failcallback) {
if (username != "") { options.user = username }
addGetOptions(options, "artist.getTags");
LastFMGetRequest(
options,
!logged_in,
callback,
failcallback
);
},
addTags : function(options, callback, failcallback) {
if (logged_in) {
addSetOptions(options, "artist.addTags");
LastFMSignedRequest(
options,
function() { callback("artist", options.tags) },
function() { failcallback("artist", options.tags) }
);
}
},
removeTag: function(options, callback, failcallback) {
if (logged_in) {
addSetOptions(options, "artist.removeTag");
LastFMSignedRequest(
options,
function() { callback("artist", options.tag); },
function() { failcallback("artist", options.tag); }
);
}
},
getSimilar: function(options, callback, failcallback) {
addGetOptions(options, "artist.getSimilar");
LastFMGetRequest(
options,
true,
callback,
failcallback,
1
)
}
}
this.user = {
getArtistTracks: function(artist, perpage, page, callback, failcallback) {
var options = { user: username,
page: page,
limit: perpage,
artist: artist
};
addGetOptions(options, "user.getArtistTracks");
LastFMGetRequest(
options,
false,
callback,
failcallback,
1
)
},
getTopArtists: function(options, callback, failcallback) {
options.user = username;
addGetOptions(options, "user.getTopArtists");
LastFMGetRequest(
options,
false,
callback,
failcallback,
1
)
},
getTopTracks: function(options, callback, failcallback) {
options.user = username;
addGetOptions(options, "user.getTopTracks");
LastFMGetRequest(
options,
false,
callback,
failcallback,
1
)
},
getRecentTracks: function(options, callback, failcallback) {
options.user = username;
options.extended = 1;
addGetOptions(options, "user.getRecentTracks");
LastFMGetRequest(
options,
false,
callback,
failcallback,
1
)
}
}
this.library = {
getArtists: function(perpage, page, callback, failcallback) {
var options = { user: username,
page: page,
limit: perpage
};
addGetOptions(options, "library.getArtists");
LastFMGetRequest(
options,
false,
callback,
failcallback,
1
)
}
}
}