stuff
This commit is contained in:
35
buildfiles/app/node_modules/lastfm/lib/lastfm/index.js
generated
vendored
Normal file
35
buildfiles/app/node_modules/lastfm/lib/lastfm/index.js
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
var RecentTracksStream = require("./recenttracks-stream"),
|
||||
LastFmSession = require("./lastfm-session"),
|
||||
LastFmUpdate = require("./lastfm-update"),
|
||||
LastFmInfo = require("./lastfm-info"),
|
||||
LastFmRequest = require("./lastfm-request");
|
||||
|
||||
var LastFmNode = exports.LastFmNode = function(options) {
|
||||
options = options || {};
|
||||
this.url = "/2.0";
|
||||
this.host = "ws.audioscrobbler.com";
|
||||
this.format = "json";
|
||||
this.secret = options.secret;
|
||||
this.api_key = options.api_key;
|
||||
this.useragent = options.useragent || "lastfm-node";
|
||||
};
|
||||
|
||||
LastFmNode.prototype.request = function(method, params) {
|
||||
return new LastFmRequest(this, method, params);
|
||||
};
|
||||
|
||||
LastFmNode.prototype.stream = function(user, options) {
|
||||
return new RecentTracksStream(this, user, options);
|
||||
};
|
||||
|
||||
LastFmNode.prototype.session = function(user, key) {
|
||||
return new LastFmSession(this, user, key);
|
||||
};
|
||||
|
||||
LastFmNode.prototype.info = function(type, options) {
|
||||
return new LastFmInfo(this, type, options);
|
||||
};
|
||||
|
||||
LastFmNode.prototype.update = function(method, session, options) {
|
||||
return new LastFmUpdate(this, method, session, options);
|
||||
};
|
45
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-base.js
generated
vendored
Normal file
45
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-base.js
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
var EventEmitter = require("events").EventEmitter
|
||||
, _ = require("underscore");
|
||||
|
||||
var LastFmBase = function() {
|
||||
EventEmitter.call(this);
|
||||
};
|
||||
|
||||
LastFmBase.prototype = Object.create(EventEmitter.prototype);
|
||||
|
||||
LastFmBase.prototype.registerHandlers = function(handlers) {
|
||||
if (typeof handlers !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
var that = this;
|
||||
_(handlers).each(function(value, key) {
|
||||
that.on(key, value);
|
||||
});
|
||||
};
|
||||
|
||||
var defaultBlacklist = ["error", "success", "handlers"];
|
||||
LastFmBase.prototype.filterParameters = function(parameters, blacklist) {
|
||||
var filteredParams = {};
|
||||
_(parameters).each(function(value, key) {
|
||||
if (isBlackListed(key)) {
|
||||
return;
|
||||
}
|
||||
filteredParams[key] = value;
|
||||
});
|
||||
return filteredParams;
|
||||
|
||||
function isBlackListed(name) {
|
||||
return _(defaultBlacklist).include(name) || _(blacklist).include(name);
|
||||
}
|
||||
};
|
||||
|
||||
LastFmBase.prototype.scheduleCallback = function(callback, delay) {
|
||||
return setTimeout(callback, delay);
|
||||
};
|
||||
|
||||
LastFmBase.prototype.cancelCallback = function(identifier) {
|
||||
clearTimeout(identifier);
|
||||
};
|
||||
|
||||
module.exports = LastFmBase;
|
43
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-info.js
generated
vendored
Normal file
43
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-info.js
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
var LastFmBase = require("./lastfm-base");
|
||||
|
||||
var LastFmInfo = function(lastfm, type, options) {
|
||||
var that = this;
|
||||
options = options || {};
|
||||
LastFmBase.call(this);
|
||||
|
||||
registerEventHandlers(options);
|
||||
requestInfo(type, options);
|
||||
|
||||
function registerEventHandlers(options) {
|
||||
that.registerHandlers(options.handlers);
|
||||
}
|
||||
|
||||
function requestInfo(type, options) {
|
||||
if (!type) {
|
||||
that.emit("error", new Error("Item type not specified"));
|
||||
return;
|
||||
}
|
||||
|
||||
var params = that.filterParameters(options)
|
||||
, method = type + ".getinfo"
|
||||
, request = lastfm.request(method, params);
|
||||
request.on("success", success);
|
||||
request.on("error", error);
|
||||
}
|
||||
|
||||
function success(response) {
|
||||
if (response[type]) {
|
||||
that.emit("success", response[type]);
|
||||
return;
|
||||
}
|
||||
that.emit("error", new Error("Unexpected error"));
|
||||
}
|
||||
|
||||
function error(error) {
|
||||
that.emit("error", error);
|
||||
}
|
||||
};
|
||||
|
||||
LastFmInfo.prototype = Object.create(LastFmBase.prototype);
|
||||
|
||||
module.exports = LastFmInfo;
|
144
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-request.js
generated
vendored
Normal file
144
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-request.js
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
if (global.GENTLY_HIJACK) require = GENTLY_HIJACK.hijack(require);
|
||||
|
||||
var http = require("http")
|
||||
, querystring = require('querystring')
|
||||
, _ = require("underscore")
|
||||
, crypto = require("crypto")
|
||||
, LastFmBase = require("./lastfm-base");
|
||||
|
||||
var WRITE_METHODS = ["album.addtags", "album.removetag", "album.share",
|
||||
"artist.addtags", "artist.removetag", "artist.share", "artist.shout",
|
||||
"event.attend", "event.share", "event.shout",
|
||||
"library.addalbum", "library.addartist", "library.addtrack",
|
||||
"library.removealbum", "library.removeartist", "library.removetrack", "library.removescrobble",
|
||||
"playlist.addtrack", "playlist.create",
|
||||
"radio.tune",
|
||||
"track.addtags", "track.ban", "track.love", "track.removetag",
|
||||
"track.scrobble", "track.share", "track.unban", "track.unlove",
|
||||
"track.updatenowplaying",
|
||||
"user.shout"],
|
||||
SIGNED_METHODS = ["auth.getmobilesession", "auth.getsession", "auth.gettoken",
|
||||
"radio.getplaylist",
|
||||
"user.getrecentstations", "user.getrecommendedartists", "user.getrecommendedevents"];
|
||||
|
||||
var LastFmRequest = module.exports = function(lastfm, method, params) {
|
||||
var that = this;
|
||||
LastFmBase.call(this);
|
||||
params = params || {};
|
||||
|
||||
that.registerHandlers(params.handlers);
|
||||
|
||||
sendRequest(lastfm.host, lastfm.url, params);
|
||||
|
||||
function sendRequest(host, url, params) {
|
||||
var httpVerb = isWriteRequest() ? "POST" : "GET"
|
||||
var requestParams = buildRequestParams(params);
|
||||
var data = querystring.stringify(requestParams);
|
||||
if (httpVerb == "GET") {
|
||||
url += "?" + data;
|
||||
}
|
||||
var options = {
|
||||
host: host,
|
||||
port: 80,
|
||||
path: url,
|
||||
method: httpVerb,
|
||||
headers: requestHeaders(httpVerb, host, data)
|
||||
};
|
||||
var req = http.request(options, chunkedResponse);
|
||||
req.on("error", function(error) {
|
||||
that.emit("error", error);
|
||||
});
|
||||
if (httpVerb == "POST") {
|
||||
req.write(data);
|
||||
}
|
||||
req.end()
|
||||
}
|
||||
|
||||
function buildRequestParams(params) {
|
||||
var requestParams = that.filterParameters(params, ["signed", "write"]);
|
||||
requestParams.method = method;
|
||||
requestParams.api_key = requestParams.api_key || lastfm.api_key;
|
||||
requestParams.format = requestParams.format || lastfm.format;
|
||||
if (params.track && typeof params.track === "object") {
|
||||
requestParams.artist = params.track.artist["#text"];
|
||||
requestParams.track = params.track.name;
|
||||
if (params.track.mbid) {
|
||||
requestParams.mbid = params.track.mbid;
|
||||
}
|
||||
if (params.track.album) {
|
||||
requestParams.album = requestParams.album || params.track.album["#text"];
|
||||
}
|
||||
}
|
||||
if (requiresSignature()) {
|
||||
requestParams.api_sig = createSignature(requestParams, lastfm.secret);
|
||||
}
|
||||
return requestParams;
|
||||
}
|
||||
|
||||
function requiresSignature() {
|
||||
return params.signed || isWriteRequest() || isSignedMethod(method);
|
||||
}
|
||||
|
||||
function isWriteRequest() {
|
||||
return params.write || isWriteMethod(method);
|
||||
}
|
||||
|
||||
function isSignedMethod(method) {
|
||||
return method && _(SIGNED_METHODS).include(method.toLowerCase());
|
||||
}
|
||||
|
||||
function isWriteMethod(method) {
|
||||
return method && _(WRITE_METHODS).include(method.toLowerCase());
|
||||
}
|
||||
|
||||
function requestHeaders(httpVerb, host, data) {
|
||||
var headers = {
|
||||
"User-Agent": lastfm.useragent
|
||||
};
|
||||
|
||||
if (httpVerb == "POST") {
|
||||
headers["Content-Length"] = data.length;
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
function chunkedResponse(response) {
|
||||
var data = "";
|
||||
response.on("data", function(chunk) {
|
||||
data += chunk.toString("utf8");
|
||||
});
|
||||
response.on("end", function() {
|
||||
if (lastfm.format !== "json") {
|
||||
that.emit("success", data);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var json = JSON.parse(data);
|
||||
if (json.error) {
|
||||
that.emit("error", json);
|
||||
return;
|
||||
}
|
||||
that.emit("success", json);
|
||||
}
|
||||
catch(e) {
|
||||
that.emit("error", e)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createSignature(params, secret) {
|
||||
var sig = "";
|
||||
Object.keys(params).sort().forEach(function(key) {
|
||||
if (key != "format") {
|
||||
var value = typeof params[key] !== "undefined" && params[key] !== null ? params[key] : "";
|
||||
sig += key + value;
|
||||
}
|
||||
});
|
||||
sig += secret;
|
||||
return crypto.createHash("md5").update(sig, "utf8").digest("hex");
|
||||
}
|
||||
};
|
||||
|
||||
LastFmRequest.prototype = Object.create(LastFmBase.prototype);
|
72
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-session.js
generated
vendored
Normal file
72
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-session.js
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
var LastFmBase = require("./lastfm-base");
|
||||
|
||||
var LastFmSession = function(lastfm, user, key) {
|
||||
var that = this;
|
||||
LastFmBase.call(this);
|
||||
user = user || "";
|
||||
key = key || "";
|
||||
|
||||
this.user = user;
|
||||
|
||||
this.key = key;
|
||||
|
||||
this.authorise = function(token, options) {
|
||||
authorise(token, options);
|
||||
};
|
||||
|
||||
this.isAuthorised = function() {
|
||||
return isAuthorised();
|
||||
}
|
||||
|
||||
function authorise(token, options) {
|
||||
options = options || { };
|
||||
|
||||
registerEventHandlers(options);
|
||||
|
||||
validateToken(token);
|
||||
}
|
||||
|
||||
function registerEventHandlers(options) {
|
||||
that.registerHandlers(options.handlers);
|
||||
}
|
||||
|
||||
function validateToken(token) {
|
||||
if (!token) {
|
||||
that.emit("error", new Error("No token supplied"));
|
||||
return;
|
||||
}
|
||||
|
||||
var params = { token: token },
|
||||
request = lastfm.request("auth.getsession", params);
|
||||
|
||||
request.on("success", authoriseSession);
|
||||
|
||||
request.on("error", bubbleError);
|
||||
}
|
||||
|
||||
function isAuthorised() {
|
||||
return that.key && that.key !== '';
|
||||
}
|
||||
|
||||
function authoriseSession(result) {
|
||||
if (!result.session) {
|
||||
that.emit("error", new Error("Unexpected error"));
|
||||
return;
|
||||
}
|
||||
setSessionDetails(result.session);
|
||||
that.emit("authorised", that);
|
||||
}
|
||||
|
||||
function setSessionDetails(session) {
|
||||
that.user = session.name;
|
||||
that.key = session.key;
|
||||
}
|
||||
|
||||
function bubbleError(error) {
|
||||
that.emit("error", error);
|
||||
}
|
||||
};
|
||||
|
||||
LastFmSession.prototype = Object.create(LastFmBase.prototype);
|
||||
|
||||
module.exports = LastFmSession;
|
104
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-update.js
generated
vendored
Normal file
104
buildfiles/app/node_modules/lastfm/lib/lastfm/lastfm-update.js
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
var _ = require("underscore")
|
||||
, LastFmBase = require("./lastfm-base")
|
||||
, retryOnErrors = [
|
||||
11, // Service offline
|
||||
16, // Temporarily unavailable
|
||||
29 // Rate limit exceeded
|
||||
]
|
||||
, retrySchedule = [
|
||||
10 * 1000, // 10 seconds
|
||||
30 * 1000, // 30 seconds
|
||||
60 * 1000, // 1 minute
|
||||
5 * 60 * 1000, // 5 minutes
|
||||
15 * 60 * 1000, // 15 minutes
|
||||
30 * 60 * 1000 // 30 minutes
|
||||
];
|
||||
|
||||
var LastFmUpdate = function(lastfm, method, session, options) {
|
||||
var that = this;
|
||||
options = options || { };
|
||||
LastFmBase.call(this);
|
||||
|
||||
registerEventHandlers(options);
|
||||
|
||||
if (!session.isAuthorised()) {
|
||||
this.emit("error", {
|
||||
error: 4,
|
||||
message: "Authentication failed"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (method !== "scrobble" && method !== "nowplaying") {
|
||||
return;
|
||||
}
|
||||
update(method, options);
|
||||
|
||||
function registerEventHandlers(options) {
|
||||
that.registerHandlers(options.handlers);
|
||||
}
|
||||
|
||||
function update(method, options) {
|
||||
if (method == "scrobble" && !options.timestamp) {
|
||||
that.emit("error", {
|
||||
error: 6,
|
||||
message: "Invalid parameters - Timestamp is required for scrobbling"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var retryCount = 0
|
||||
, params = buildRequestParams(options)
|
||||
, requestMethod = method == "scrobble" ? "track.scrobble" : "track.updateNowPlaying";
|
||||
makeRequest();
|
||||
|
||||
function makeRequest() {
|
||||
var request = lastfm.request(requestMethod, params);
|
||||
request.on("error", errorCallback);
|
||||
request.on("success", successCallback);
|
||||
}
|
||||
|
||||
function successCallback(response) {
|
||||
if (response) {
|
||||
that.emit("success", options.track);
|
||||
}
|
||||
}
|
||||
|
||||
function errorCallback(error) {
|
||||
if (shouldBeRetried(error)) {
|
||||
var delay = delayFor(retryCount++)
|
||||
, retry = {
|
||||
error: error.error,
|
||||
message: error.message,
|
||||
delay: delay
|
||||
};
|
||||
that.emit("retrying", retry);
|
||||
that.scheduleCallback(makeRequest, delay);
|
||||
return;
|
||||
}
|
||||
bubbleError(error);
|
||||
}
|
||||
|
||||
function shouldBeRetried(error) {
|
||||
return method == "scrobble" && _(retryOnErrors).include(error.error)
|
||||
}
|
||||
}
|
||||
|
||||
function bubbleError(error) {
|
||||
that.emit("error", error);
|
||||
}
|
||||
|
||||
function buildRequestParams(params) {
|
||||
var requestParams = that.filterParameters(params);
|
||||
requestParams.sk = session.key;
|
||||
return requestParams;
|
||||
}
|
||||
|
||||
function delayFor(retryCount) {
|
||||
var index = Math.min(retryCount, retrySchedule.length - 1);
|
||||
return retrySchedule[index];
|
||||
}
|
||||
}
|
||||
|
||||
LastFmUpdate.prototype = Object.create(LastFmBase.prototype);
|
||||
|
||||
module.exports = LastFmUpdate;
|
111
buildfiles/app/node_modules/lastfm/lib/lastfm/recenttracks-stream.js
generated
vendored
Normal file
111
buildfiles/app/node_modules/lastfm/lib/lastfm/recenttracks-stream.js
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
var LastFmBase = require("./lastfm-base");
|
||||
|
||||
var RecentTracksStream = module.exports = function(lastfm, user, options) {
|
||||
var that = this;
|
||||
LastFmBase.call(this);
|
||||
options = options || {};
|
||||
|
||||
var rate = 10
|
||||
, isStreaming = false
|
||||
, timeout
|
||||
, lastPlay = null
|
||||
, nowPlaying = null;
|
||||
|
||||
registerEventHandlers(options);
|
||||
|
||||
if (options.autostart) {
|
||||
start();
|
||||
}
|
||||
|
||||
this.start = function() {
|
||||
start();
|
||||
}
|
||||
|
||||
this.stop = function() {
|
||||
stop();
|
||||
}
|
||||
|
||||
this.isStreaming = function() {
|
||||
return isStreaming;
|
||||
}
|
||||
|
||||
function registerEventHandlers(options) {
|
||||
that.registerHandlers(options.handlers);
|
||||
}
|
||||
|
||||
function start() {
|
||||
isStreaming = true;
|
||||
check();
|
||||
|
||||
function check() {
|
||||
var request = lastfm.request("user.getrecenttracks", {
|
||||
user: user,
|
||||
limit: 1
|
||||
});
|
||||
request.on("success", handleSuccess);
|
||||
request.on("error", bubbleError);
|
||||
if (isStreaming) {
|
||||
timeout = that.scheduleCallback(check, rate * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function handleSuccess(data) {
|
||||
if (!data || !data.recenttracks || !data.recenttracks.track) {
|
||||
that.emit("error", new Error("Unexpected response"));
|
||||
return;
|
||||
}
|
||||
|
||||
var tracks = data.recenttracks.track;
|
||||
if (tracks instanceof Array) {
|
||||
processNowPlaying(tracks[0]);
|
||||
processLastPlay(tracks[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
var track = tracks;
|
||||
if (track["@attr"] && track["@attr"]["nowplaying"]) {
|
||||
processNowPlaying(track);
|
||||
return;
|
||||
}
|
||||
|
||||
processLastPlay(track);
|
||||
if (nowPlaying) {
|
||||
that.emit("stoppedPlaying", nowPlaying);
|
||||
nowPlaying = null;
|
||||
}
|
||||
}
|
||||
|
||||
function bubbleError(error) {
|
||||
that.emit("error", error);
|
||||
}
|
||||
}
|
||||
|
||||
function processNowPlaying(track) {
|
||||
var sameTrack = (nowPlaying && nowPlaying.name == track.name);
|
||||
if (!sameTrack) {
|
||||
nowPlaying = track;
|
||||
that.emit("nowPlaying", track);
|
||||
}
|
||||
}
|
||||
|
||||
function processLastPlay(track) {
|
||||
if (!lastPlay) {
|
||||
lastPlay = track;
|
||||
that.emit("lastPlayed", track);
|
||||
return;
|
||||
}
|
||||
|
||||
var sameTrack = (lastPlay.name == track.name);
|
||||
if (!sameTrack) {
|
||||
lastPlay = track;
|
||||
that.emit("scrobbled", track);
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
that.cancelCallback(timeout);
|
||||
isStreaming = false;
|
||||
}
|
||||
};
|
||||
|
||||
RecentTracksStream.prototype = Object.create(LastFmBase.prototype);
|
Reference in New Issue
Block a user