Skip to content

Instantly share code, notes, and snippets.

@vr000m
Created November 17, 2012 00:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vr000m/4092220 to your computer and use it in GitHub Desktop.
Save vr000m/4092220 to your computer and use it in GitHub Desktop.
/*
History.js Native Adapter
@author Benjamin Arthur Lupton <contact@balupton.com>
@copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
@license New BSD License <http://creativecommons.org/licenses/BSD/>
History.getInternetExplorerMajorVersion()
Get's the major version of Internet Explorer
@return {integer}
@license Public Domain
@author Benjamin Arthur Lupton <contact@balupton.com>
@author James Padolsey <https://gist.github.com/527683>
History.isInternetExplorer()
Are we using Internet Explorer?
@return {boolean}
@license Public Domain
@author Benjamin Arthur Lupton <contact@balupton.com>
History.js Core
@author Benjamin Arthur Lupton <contact@balupton.com>
@copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
@license New BSD License <http://creativecommons.org/licenses/BSD/>
History.js HTML4 Support
Depends on the HTML5 Support
@author Benjamin Arthur Lupton <contact@balupton.com>
@copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
@license New BSD License <http://creativecommons.org/licenses/BSD/>
SWFObject v2.2 <http://code.google.com/p/swfobject/> is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>.
*/
(function(d, h) {
var f = d.History = d.History || {};
if (typeof f.Adapter !== "undefined") throw Error("History.js Adapter has already been loaded...");
f.Adapter = {
handlers: {},
_uid: 1,
uid: function(b) {
return b._uid || (b._uid = f.Adapter._uid++)
},
bind: function(b, c, a) {
var g = f.Adapter.uid(b);
f.Adapter.handlers[g] = f.Adapter.handlers[g] || {};
f.Adapter.handlers[g][c] = f.Adapter.handlers[g][c] || [];
f.Adapter.handlers[g][c].push(a);
b["on" + c] = function(a, b) {
return function(c) {
f.Adapter.trigger(a, b, c)
}
}(b, c)
},
trigger: function(b, c, a) {
var a = a || {},
b = f.Adapter.uid(b),
g, i;
f.Adapter.handlers[b] = f.Adapter.handlers[b] || {};
f.Adapter.handlers[b][c] = f.Adapter.handlers[b][c] || [];
for (g = 0, i = f.Adapter.handlers[b][c].length; g < i; ++g) f.Adapter.handlers[b][c][g].apply(this, [a])
},
extractEventData: function(b, c) {
return c && c[b] || h
},
onDomLoad: function(b) {
var c = d.setTimeout(function() {
b()
}, 2E3);
d.onload = function() {
clearTimeout(c);
b()
}
}
};
typeof f.init !== "undefined" && f.init()
})(window);
(function(d, h) {
var f = d.console || h,
b = d.document,
c = d.navigator,
a = d.sessionStorage || !1,
g = d.setTimeout,
i = d.clearTimeout,
n = d.setInterval,
l = d.clearInterval,
m = d.JSON,
o = d.alert,
k = d.History = d.History || {},
p = d.history;
m.stringify = m.stringify || m.encode;
m.parse = m.parse || m.decode;
if (typeof k.init !== "undefined") throw Error("History.js Core has already been loaded...");
k.init = function() {
if (typeof k.Adapter === "undefined") return !1;
typeof k.initCore !== "undefined" && k.initCore();
typeof k.initHtml4 !== "undefined" && k.initHtml4();
return !0
};
k.initCore = function() {
if (typeof k.initCore.initialized !== "undefined") return !1;
else k.initCore.initialized = !0;
k.options = k.options || {};
k.options.hashChangeInterval = k.options.hashChangeInterval || 100;
k.options.safariPollInterval = k.options.safariPollInterval || 500;
k.options.doubleCheckInterval = k.options.doubleCheckInterval || 500;
k.options.storeInterval = k.options.storeInterval || 1E3;
k.options.busyDelay = k.options.busyDelay || 250;
k.options.debug = k.options.debug || !1;
k.options.initialTitle = k.options.initialTitle || b.title;
k.intervalList = [];
k.clearAllIntervals = function() {
var a, b = k.intervalList;
if (typeof b !== "undefined" && b !== null) {
for (a = 0; a < b.length; a++) l(b[a]);
k.intervalList = null
}
};
k.debug = function() {
k.options.debug && k.log.apply(k, arguments)
};
k.log = function() {
var a = !(typeof f === "undefined" || typeof f.log === "undefined" || typeof f.log.apply === "undefined"),
c = b.getElementById("log"),
g, i, l, d;
a ? (i = Array.prototype.slice.call(arguments), g = i.shift(), typeof f.debug !== "undefined" ? f.debug.apply(f, [g, i]) : f.log.apply(f, [g, i])) : g = "\n" + arguments[0] + "\n";
for (i = 1, l = arguments.length; i < l; ++i) {
d = arguments[i];
if (typeof d === "object" && typeof m !== "undefined") try {
d = m.stringify(d)
} catch (n) {}
g += "\n" + d + "\n"
}
c ? (c.value += g + "\n-----\n", c.scrollTop = c.scrollHeight - c.clientHeight) : a || o(g);
return !0
};
k.getInternetExplorerMajorVersion = function() {
return k.getInternetExplorerMajorVersion.cached = typeof k.getInternetExplorerMajorVersion.cached !== "undefined" ? k.getInternetExplorerMajorVersion.cached : function() {
for (var a = 3, c = b.createElement("div"), g = c.getElementsByTagName("i");
(c.innerHTML = "<\!--[if gt IE " + ++a + "]><i></i><![endif]--\>") && g[0];);
return a > 4 ? a : !1
}()
};
k.isInternetExplorer = function() {
return k.isInternetExplorer.cached = typeof k.isInternetExplorer.cached !== "undefined" ? k.isInternetExplorer.cached : Boolean(k.getInternetExplorerMajorVersion())
};
k.emulated = {
pushState: !Boolean(d.history && d.history.pushState && d.history.replaceState && !(/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(c.userAgent) || /AppleWebKit\/5([0-2]|3[0-2])/i.test(c.userAgent))),
hashChange: Boolean(!("onhashchange" in d || "onhashchange" in b) || k.isInternetExplorer() && k.getInternetExplorerMajorVersion() < 8)
};
k.enabled = !k.emulated.pushState;
k.bugs = {
setHash: Boolean(!k.emulated.pushState && c.vendor === "Apple Computer, Inc." && /AppleWebKit\/5([0-2]|3[0-3])/.test(c.userAgent)),
safariPoll: Boolean(!k.emulated.pushState && c.vendor === "Apple Computer, Inc." && /AppleWebKit\/5([0-2]|3[0-3])/.test(c.userAgent)),
ieDoubleCheck: Boolean(k.isInternetExplorer() && k.getInternetExplorerMajorVersion() < 8),
hashEscape: Boolean(k.isInternetExplorer() && k.getInternetExplorerMajorVersion() < 7)
};
k.isEmptyObject = function(a) {
for (var b in a) return !1;
return !0
};
k.cloneObject = function(a) {
a ? (a = m.stringify(a), a = m.parse(a)) : a = {};
return a
};
k.getRootUrl = function() {
var a = b.location.protocol + "//" + (b.location.hostname || b.location.host);
b.location.port && (a += ":" + b.location.port);
a += "/";
return a
};
k.getBaseHref = function() {
var a = b.getElementsByTagName("base"),
c = null,
c = "";
a.length === 1 && (c = a[0], c = c.href.replace(/[^\/]+$/, ""));
(c = c.replace(/\/+$/, "")) && (c += "/");
return c
};
k.getBaseUrl = function() {
return k.getBaseHref() || k.getBasePageUrl() || k.getRootUrl()
};
k.getPageUrl = function() {
return ((k.getState(!1, !1) || {}).url || b.location.href).replace(/\/+$/, "").replace(/[^\/]+$/, function(a) {
return /\./.test(a) ? a : a + "/"
})
};
k.getBasePageUrl = function() {
return b.location.href.replace(/[#\?].*/, "").replace(/[^\/]+$/, function(a) {
return /[^\/]$/.test(a) ? "" : a
}).replace(/\/+$/, "") + "/"
};
k.getFullUrl = function(a, b) {
var c = a,
g = a.substring(0, 1),
b = typeof b === "undefined" ? !0 : b;
/[a-z]+\:\/\//.test(a) || (c = g === "/" ? k.getRootUrl() + a.replace(/^\/+/, "") : g === "#" ? k.getPageUrl().replace(/#.*/, "") + a : g === "?" ? k.getPageUrl().replace(/[\?#].*/, "") + a : b ? k.getBaseUrl() + a.replace(/^(\.\/)+/, "") : k.getBasePageUrl() + a.replace(/^(\.\/)+/, ""));
return c.replace(/\#$/, "")
};
k.getShortUrl = function(a) {
var b = k.getBaseUrl(),
c = k.getRootUrl();
k.emulated.pushState && (a = a.replace(b, ""));
a = a.replace(c, "/");
k.isTraditionalAnchor(a) && (a = "./" + a);
return a = a.replace(/^(\.\/)+/g, "./").replace(/\#$/, "")
};
k.store = {};
k.idToState = k.idToState || {};
k.stateToId = k.stateToId || {};
k.urlToId = k.urlToId || {};
k.storedStates = k.storedStates || [];
k.savedStates = k.savedStates || [];
k.normalizeStore = function() {
k.store.idToState = k.store.idToState || {};
k.store.urlToId = k.store.urlToId || {};
k.store.stateToId = k.store.stateToId || {}
};
k.getState = function(a, b) {
typeof a === "undefined" && (a = !0);
typeof b === "undefined" && (b = !0);
var c = k.getLastSavedState();
!c && b && (c = k.createStateObject());
if (a) c = k.cloneObject(c), c.url = c.cleanUrl || c.url;
return c
};
k.getIdByState = function(a) {
var b = k.extractId(a.url),
c;
if (!b) if (c = k.getStateString(a), typeof k.stateToId[c] !== "undefined") b = k.stateToId[c];
else if (typeof k.store.stateToId[c] !== "undefined") b = k.store.stateToId[c];
else {
for (;;) if (b = (new Date).getTime() + String(Math.random()).replace(/\D/g, ""), typeof k.idToState[b] === "undefined" && typeof k.store.idToState[b] === "undefined") break;
k.stateToId[c] = b;
k.idToState[b] = a
}
return b
};
k.normalizeState = function(a) {
var c;
if (!a || typeof a !== "object") a = {};
if (typeof a.normalized !== "undefined") return a;
if (!a.data || typeof a.data !== "object") a.data = {};
c = {
normalized: !0
};
c.title = a.title || "";
c.url = k.getFullUrl(k.unescapeString(a.url || b.location.href));
c.hash = k.getShortUrl(c.url);
c.data = k.cloneObject(a.data);
c.id = k.getIdByState(c);
c.cleanUrl = c.url.replace(/\??\&_suid.*/, "");
c.url = c.cleanUrl;
a = !k.isEmptyObject(c.data);
if (c.title || a) c.hash = k.getShortUrl(c.url).replace(/\??\&_suid.*/, ""), /\?/.test(c.hash) || (c.hash += "?"), c.hash += "&_suid=" + c.id;
c.hashedUrl = k.getFullUrl(c.hash);
if ((k.emulated.pushState || k.bugs.safariPoll) && k.hasUrlDuplicate(c)) c.url = c.hashedUrl;
return c
};
k.createStateObject = function(a, b, c) {
a = {
data: a,
title: b,
url: c
};
return a = k.normalizeState(a)
};
k.getStateById = function(a) {
a = String(a);
return k.idToState[a] || k.store.idToState[a] || h
};
k.getStateString = function(a) {
a = {
data: k.normalizeState(a).data,
title: a.title,
url: a.url
};
return m.stringify(a)
};
k.getStateId = function(a) {
return k.normalizeState(a).id
};
k.getHashByState = function(a) {
return k.normalizeState(a).hash
};
k.extractId = function(a) {
return ((a = /(.*)\&_suid=([0-9]+)$/.exec(a)) ? String(a[2] || "") : "") || !1
};
k.isTraditionalAnchor = function(a) {
return !/[\/\?\.]/.test(a)
};
k.extractState = function(a, b) {
var c = null,
g, i, b = b || !1;
(g = k.extractId(a)) && (c = k.getStateById(g));
c || (i = k.getFullUrl(a), (g = k.getIdByUrl(i) || !1) && (c = k.getStateById(g)), !c && b && !k.isTraditionalAnchor(a) && (c = k.createStateObject(null, null, i)));
return c
};
k.getIdByUrl = function(a) {
return k.urlToId[a] || k.store.urlToId[a] || h
};
k.getLastSavedState = function() {
return k.savedStates[k.savedStates.length - 1] || h
};
k.getLastStoredState = function() {
return k.storedStates[k.storedStates.length - 1] || h
};
k.hasUrlDuplicate = function(a) {
var b = !1;
return b = (b = k.extractState(a.url)) && b.id !== a.id
};
k.storeState = function(a) {
k.urlToId[a.url] = a.id;
k.storedStates.push(k.cloneObject(a));
return a
};
k.isLastSavedState = function(a) {
var b = !1;
if (k.savedStates.length) a = a.id, b = k.getLastSavedState(), b = b.id, b = a === b;
return b
};
k.saveState = function(a) {
if (k.isLastSavedState(a)) return !1;
k.savedStates.push(k.cloneObject(a));
return !0
};
k.getStateByIndex =
function(a) {
var b = null;
return b = typeof a === "undefined" ? k.savedStates[k.savedStates.length - 1] : a < 0 ? k.savedStates[k.savedStates.length + a] : k.savedStates[a]
};
k.getHash = function() {
return k.unescapeHash(b.location.hash)
};
k.unescapeString = function(a) {
return a
};
k.unescapeHash = function(a) {
a = k.normalizeHash(a);
return a = k.unescapeString(a)
};
k.normalizeHash = function(a) {
return a.replace(/[^#]*#/, "").replace(/#.*/, "")
};
k.setHash = function(a, c) {
var g, i;
if (c !== !1 && k.busy()) return k.pushQueue({
scope: k,
callback: k.setHash,
args: arguments,
queue: c
}), !1;
g = k.escapeHash(a);
k.busy(!0);
if ((i = k.extractState(a, !0)) && !k.emulated.pushState) k.pushState(i.data, i.title, i.url, !1);
else if (b.location.hash !== g) k.bugs.setHash ? (i = k.getPageUrl(), k.pushState(null, null, i + "#" + g, !1)) : b.location.hash = g;
return k
};
k.escapeHash = function(a) {
a = k.normalizeHash(a);
a = d.escape(a);
k.bugs.hashEscape || (a = a.replace(/\%21/g, "!").replace(/\%26/g, "&").replace(/\%3D/g, "=").replace(/\%3F/g, "?"));
return a
};
k.getHashByUrl = function(a) {
a = String(a).replace(/([^#]*)#?([^#]*)#?(.*)/, "$2");
return a = k.unescapeHash(a)
};
k.setTitle = function(a) {
var c = a.title,
g;
c || (g = k.getStateByIndex(0)) && g.url === a.url && (c = g.title || k.options.initialTitle);
try {
b.getElementsByTagName("title")[0].innerHTML = c.replace("<", "&lt;").replace(">", "&gt;").replace(" & ", " &amp; ")
} catch (i) {}
b.title = c;
return k
};
k.queues = [];
k.busy = function(a) {
if (typeof a !== "undefined") k.busy.flag = a;
else if (typeof k.busy.flag === "undefined") k.busy.flag = !1;
if (!k.busy.flag) {
i(k.busy.timeout);
var b = function() {
var a, c;
if (!k.busy.flag) for (a =
k.queues.length - 1; a >= 0; --a) if (c = k.queues[a], c.length !== 0) c = c.shift(), k.fireQueueItem(c), k.busy.timeout = g(b, k.options.busyDelay)
};
k.busy.timeout = g(b, k.options.busyDelay)
}
return k.busy.flag
};
k.busy.flag = !1;
k.fireQueueItem = function(a) {
return a.callback.apply(a.scope || k, a.args || [])
};
k.pushQueue = function(a) {
k.queues[a.queue || 0] = k.queues[a.queue || 0] || [];
k.queues[a.queue || 0].push(a);
return k
};
k.queue = function(a, b) {
typeof a === "function" && (a = {
callback: a
});
if (typeof b !== "undefined") a.queue = b;
k.busy() ? k.pushQueue(a) : k.fireQueueItem(a);
return k
};
k.clearQueue = function() {
k.busy.flag = !1;
k.queues = [];
return k
};
k.stateChanged = !1;
k.doubleChecker = !1;
k.doubleCheckComplete = function() {
k.stateChanged = !0;
k.doubleCheckClear();
return k
};
k.doubleCheckClear = function() {
if (k.doubleChecker) i(k.doubleChecker), k.doubleChecker = !1;
return k
};
k.doubleCheck = function(a) {
k.stateChanged = !1;
k.doubleCheckClear();
if (k.bugs.ieDoubleCheck) k.doubleChecker = g(function() {
k.doubleCheckClear();
k.stateChanged || a();
return !0
}, k.options.doubleCheckInterval);
return k
};
k.safariStatePoll = function() {
var a = k.extractState(b.location.href);
if (!k.isLastSavedState(a)) return a || k.createStateObject(), k.Adapter.trigger(d, "popstate"), k
};
k.back = function(a) {
if (a !== !1 && k.busy()) return k.pushQueue({
scope: k,
callback: k.back,
args: arguments,
queue: a
}), !1;
k.busy(!0);
k.doubleCheck(function() {
k.back(!1)
});
p.go(-1);
return !0
};
k.forward = function(a) {
if (a !== !1 && k.busy()) return k.pushQueue({
scope: k,
callback: k.forward,
args: arguments,
queue: a
}), !1;
k.busy(!0);
k.doubleCheck(function() {
k.forward(!1)
});
p.go(1);
return !0
};
k.go = function(a, b) {
var c;
if (a > 0) for (c = 1; c <= a; ++c) k.forward(b);
else if (a < 0) for (c = -1; c >= a; --c) k.back(b);
else
throw Error("History.go: History.go requires a positive or negative integer passed.");
return k
};
if (k.emulated.pushState) {
var q = function() {};
k.pushState = k.pushState || q;
k.replaceState = k.replaceState || q
} else k.onPopState = function(a, c) {
var g = !1,
g = !1;
k.doubleCheckComplete();
if (g = k.getHash()) return (g = k.extractState(g || b.location.href, !0)) ? k.replaceState(g.data, g.title, g.url, !1) : (k.Adapter.trigger(d, "anchorchange"), k.busy(!1)), k.expectedStateId = !1;
(g = (g = k.Adapter.extractEventData("state", a, c) || !1) ? k.getStateById(g) : k.expectedStateId ? k.getStateById(k.expectedStateId) : k.extractState(b.location.href)) || (g = k.createStateObject(null, null, b.location.href));
k.expectedStateId = !1;
if (k.isLastSavedState(g)) return k.busy(!1), !1;
k.storeState(g);
k.saveState(g);
k.setTitle(g);
k.Adapter.trigger(d, "statechange");
k.busy(!1);
return !0
}, k.Adapter.bind(d, "popstate", k.onPopState), k.pushState = function(a, b, c, g) {
if (k.getHashByUrl(c) && k.emulated.pushState) throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");
if (g !== !1 && k.busy()) return k.pushQueue({
scope: k,
callback: k.pushState,
args: arguments,
queue: g
}), !1;
k.busy(!0);
var i = k.createStateObject(a, b, c);
k.isLastSavedState(i) ? k.busy(!1) : (k.storeState(i), k.expectedStateId = i.id, p.pushState(i.id, i.title, i.url), k.Adapter.trigger(d, "popstate"));
return !0
}, k.replaceState = function(a, b, c, g) {
if (k.getHashByUrl(c) && k.emulated.pushState) throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");
if (g !== !1 && k.busy()) return k.pushQueue({
scope: k,
callback: k.replaceState,
args: arguments,
queue: g
}), !1;
k.busy(!0);
var i = k.createStateObject(a, b, c);
k.isLastSavedState(i) ? k.busy(!1) : (k.storeState(i), k.expectedStateId = i.id, p.replaceState(i.id, i.title, i.url), k.Adapter.trigger(d, "popstate"));
return !0
};
if (a) try {
k.store = m.parse(a.getItem("History.store")) || {}
} catch (s) {
k.store = {}
} else k.store = {};
k.normalizeStore();
k.Adapter.bind(d, "beforeunload", k.clearAllIntervals);
k.Adapter.bind(d, "unload", k.clearAllIntervals);
k.saveState(k.storeState(k.extractState(b.location.href, !0)));
if (a) k.onUnload = function() {
var b, c;
try {
b = m.parse(a.getItem("History.store")) || {}
} catch (g) {
b = {}
}
b.idToState = b.idToState || {};
b.urlToId = b.urlToId || {};
b.stateToId = b.stateToId || {};
for (c in k.idToState) k.idToState.hasOwnProperty(c) && (b.idToState[c] = k.idToState[c]);
for (c in k.urlToId) k.urlToId.hasOwnProperty(c) && (b.urlToId[c] = k.urlToId[c]);
for (c in k.stateToId) k.stateToId.hasOwnProperty(c) && (b.stateToId[c] = k.stateToId[c]);
k.store = b;
k.normalizeStore();
a.setItem("History.store", m.stringify(b))
}, k.intervalList.push(n(k.onUnload, k.options.storeInterval)), k.Adapter.bind(d, "beforeunload", k.onUnload), k.Adapter.bind(d, "unload", k.onUnload);
if (!k.emulated.pushState && (k.bugs.safariPoll && k.intervalList.push(n(k.safariStatePoll, k.options.safariPollInterval)), c.vendor === "Apple Computer, Inc." || (c.appCodeName || "") === "Mozilla")) if (k.Adapter.bind(d, "hashchange", function() {
k.Adapter.trigger(d, "popstate")
}), k.getHash()) k.Adapter.onDomLoad(function() {
k.Adapter.trigger(d, "hashchange")
})
};
k.init()
})(window);
(function(d) {
var h = d.document,
f = d.setInterval || f,
b = d.History = d.History || {};
if (typeof b.initHtml4 !== "undefined") throw Error("History.js HTML4 Support has already been loaded...");
b.initHtml4 = function() {
if (typeof b.initHtml4.initialized !== "undefined") return !1;
else b.initHtml4.initialized = !0;
b.enabled = !0;
b.savedHashes = [];
b.isLastHash = function(c) {
var a = b.getHashByIndex();
return c === a
};
b.saveHash = function(c) {
if (b.isLastHash(c)) return !1;
b.savedHashes.push(c);
return !0
};
b.getHashByIndex = function(c) {
var a =
null;
return a = typeof c === "undefined" ? b.savedHashes[b.savedHashes.length - 1] : c < 0 ? b.savedHashes[b.savedHashes.length + c] : b.savedHashes[c]
};
b.discardedHashes = {};
b.discardedStates = {};
b.discardState = function(c, a, g) {
var i = b.getHashByState(c);
b.discardedStates[i] = {
discardedState: c,
backState: g,
forwardState: a
};
return !0
};
b.discardHash = function(c, a, g) {
b.discardedHashes[c] = {
discardedHash: c,
backState: g,
forwardState: a
};
return !0
};
b.discardedState = function(c) {
c = b.getHashByState(c);
return b.discardedStates[c] || !1
};
b.discardedHash = function(c) {
return b.discardedHashes[c] || !1
};
b.recycleState = function(c) {
var a = b.getHashByState(c);
b.discardedState(c) && delete b.discardedStates[a];
return !0
};
if (b.emulated.hashChange) b.hashChangeInit = function() {
b.checkerFunction = null;
var c = "",
a, g, i;
b.isInternetExplorer() ? (a = h.createElement("iframe"), a.setAttribute("id", "historyjs-iframe"), a.style.display = "none", h.body.appendChild(a), a.contentWindow.document.open(), a.contentWindow.document.close(), g = "", i = !1, b.checkerFunction = function() {
if (i) return !1;
i = !0;
var n = b.getHash() || "",
l = b.unescapeHash(a.contentWindow.document.location.hash) || "";
if (n !== c) {
c = n;
if (l !== n) g = n, a.contentWindow.document.open(), a.contentWindow.document.close(), a.contentWindow.document.location.hash = b.escapeHash(n);
b.Adapter.trigger(d, "hashchange")
} else l !== g && (g = l, b.setHash(l, !1));
i = !1;
return !0
}) : b.checkerFunction = function() {
var a = b.getHash();
a !== c && (c = a, b.Adapter.trigger(d, "hashchange"));
return !0
};
b.intervalList.push(f(b.checkerFunction, b.options.hashChangeInterval));
return !0
}, b.Adapter.onDomLoad(b.hashChangeInit);
if (b.emulated.pushState) b.onHashChange = function(c) {
var a = b.getHashByUrl(c && c.newURL || h.location.href),
c = null;
if (b.isLastHash(a)) return b.busy(!1), !1;
b.doubleCheckComplete();
b.saveHash(a);
if (a && b.isTraditionalAnchor(a)) return b.Adapter.trigger(d, "anchorchange"), b.busy(!1), !1;
c = b.extractState(b.getFullUrl(a || h.location.href, !1), !0);
if (b.isLastSavedState(c)) return b.busy(!1), !1;
b.getHashByState(c);
if (a = b.discardedState(c)) return b.getHashByIndex(-2) === b.getHashByState(a.forwardState) ? b.back(!1) : b.forward(!1), !1;
b.pushState(c.data, c.title, c.url, !1);
return !0
}, b.Adapter.bind(d, "hashchange", b.onHashChange), b.pushState = function(c, a, g, i) {
if (b.getHashByUrl(g)) throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");
if (i !== !1 && b.busy()) return b.pushQueue({
scope: b,
callback: b.pushState,
args: arguments,
queue: i
}), !1;
b.busy(!0);
var n = b.createStateObject(c, a, g),
l = b.getHashByState(n),
f = b.getState(!1),
f = b.getHashByState(f),
o = b.getHash();
b.storeState(n);
b.expectedStateId =
n.id;
b.recycleState(n);
b.setTitle(n);
if (l === f) return b.busy(!1), !1;
if (l !== o && l !== b.getShortUrl(h.location.href)) return b.setHash(l, !1), !1;
b.saveState(n);
b.Adapter.trigger(d, "statechange");
b.busy(!1);
return !0
}, b.replaceState = function(c, a, g, i) {
if (b.getHashByUrl(g)) throw Error("History.js does not support states with fragement-identifiers (hashes/anchors).");
if (i !== !1 && b.busy()) return b.pushQueue({
scope: b,
callback: b.replaceState,
args: arguments,
queue: i
}), !1;
b.busy(!0);
var d = b.createStateObject(c, a, g),
l = b.getState(!1),
f = b.getStateByIndex(-2);
b.discardState(l, d, f);
b.pushState(d.data, d.title, d.url, !1);
return !0
};
if (b.emulated.pushState && b.getHash() && !b.emulated.hashChange) b.Adapter.onDomLoad(function() {
b.Adapter.trigger(d, "hashchange")
})
};
typeof b.init !== "undefined" && b.init()
})(window);
var swfobject = function() {
function d() {
if (!L) {
try {
var a = z.getElementsByTagName("body")[0].appendChild(z.createElement("span"));
a.parentNode.removeChild(a)
} catch (b) {
return
}
L = !0;
for (var a = H.length, c = 0; c < a; c++) H[c]()
}
}
function h(a) {
L ? a() : H[H.length] = a
}
function f(a) {
if (typeof x.addEventListener != v) x.addEventListener("load", a, !1);
else if (typeof z.addEventListener != v) z.addEventListener("load", a, !1);
else if (typeof x.attachEvent != v) p(x, "onload", a);
else if (typeof x.onload == "function") {
var b = x.onload;
x.onload =
function() {
b();
a()
}
} else x.onload = a
}
function b() {
var a = z.getElementsByTagName("body")[0],
b = z.createElement(t);
b.setAttribute("type", y);
var g = a.appendChild(b);
if (g) {
var i = 0;
(function() {
if (typeof g.GetVariable != v) {
var l = g.GetVariable("$version");
if (l) l = l.split(" ")[1].split(","), A.pv = [parseInt(l[0], 10), parseInt(l[1], 10), parseInt(l[2], 10)]
} else if (i < 10) {
i++;
setTimeout(arguments.callee, 10);
return
}
a.removeChild(b);
g = null;
c()
})()
} else c()
}
function c() {
var b = E.length;
if (b > 0) for (var c = 0; c < b; c++) {
var l = E[c].id,
d = E[c].callbackFn,
f = {
success: !1,
id: l
};
if (A.pv[0] > 0) {
var h = k(l);
if (h) if (q(E[c].swfVersion) && !(A.wk && A.wk < 312)) {
if (u(l, !0), d) f.success = !0, f.ref = a(l), d(f)
} else if (E[c].expressInstall && g()) {
f = {};
f.data = E[c].expressInstall;
f.width = h.getAttribute("width") || "0";
f.height = h.getAttribute("height") || "0";
if (h.getAttribute("class")) f.styleclass = h.getAttribute("class");
if (h.getAttribute("align")) f.align = h.getAttribute("align");
for (var o = {}, h = h.getElementsByTagName("param"), m = h.length, p = 0; p < m; p++) h[p].getAttribute("name").toLowerCase() != "movie" && (o[h[p].getAttribute("name")] = h[p].getAttribute("value"));
i(f, o, l, d)
} else n(h), d && d(f)
} else if (u(l, !0), d) {
if ((l = a(l)) && typeof l.SetVariable != v) f.success = !0, f.ref = l;
d(f)
}
}
}
function a(a) {
var b = null;
if ((a = k(a)) && a.nodeName == "OBJECT") typeof a.SetVariable != v ? b = a : (a = a.getElementsByTagName(t)[0]) && (b = a);
return b
}
function g() {
return !N && q("6.0.65") && (A.win || A.mac) && !(A.wk && A.wk < 312)
}
function i(a, b, c, g) {
N = !0;
J = g || null;
O = {
success: !1,
id: c
};
var i = k(c);
if (i) {
i.nodeName == "OBJECT" ? (G = l(i), I = null) : (G = i, I =
c);
a.id = C;
if (typeof a.width == v || !/%$/.test(a.width) && parseInt(a.width, 10) < 310) a.width = "310";
if (typeof a.height == v || !/%$/.test(a.height) && parseInt(a.height, 10) < 137) a.height = "137";
z.title = z.title.slice(0, 47) + " - Flash Player Installation";
g = A.ie && A.win ? "ActiveX" : "PlugIn";
g = "MMredirectURL=" + x.location.toString().replace(/&/g, "%26") + "&MMplayerType=" + g + "&MMdoctitle=" + z.title;
typeof b.flashvars != v ? b.flashvars += "&" + g : b.flashvars = g;
if (A.ie && A.win && i.readyState != 4) g = z.createElement("div"), c += "SWFObjectNew", g.setAttribute("id", c), i.parentNode.insertBefore(g, i), i.style.display = "none", function() {
i.readyState == 4 ? i.parentNode.removeChild(i) : setTimeout(arguments.callee, 10)
}();
m(a, b, c)
}
}
function n(a) {
if (A.ie && A.win && a.readyState != 4) {
var b = z.createElement("div");
a.parentNode.insertBefore(b, a);
b.parentNode.replaceChild(l(a), b);
a.style.display = "none";
(function() {
a.readyState == 4 ? a.parentNode.removeChild(a) : setTimeout(arguments.callee, 10)
})()
} else a.parentNode.replaceChild(l(a), a)
}
function l(a) {
var b = z.createElement("div");
if (A.win && A.ie) b.innerHTML = a.innerHTML;
else if (a = a.getElementsByTagName(t)[0]) if (a = a.childNodes) for (var c = a.length, g = 0; g < c; g++)!(a[g].nodeType == 1 && a[g].nodeName == "PARAM") && a[g].nodeType != 8 && b.appendChild(a[g].cloneNode(!0));
return b
}
function m(a, b, c) {
var g, i = k(c);
if (A.wk && A.wk < 312) return g;
if (i) {
if (typeof a.id == v) a.id = c;
if (A.ie && A.win) {
var l = "",
d;
for (d in a) if (a[d] != Object.prototype[d]) d.toLowerCase() == "data" ? b.movie = a[d] : d.toLowerCase() == "styleclass" ? l += ' class="' + a[d] + '"' : d.toLowerCase() != "classid" && (l += " " + d + '="' + a[d] + '"');
d = "";
for (var f in b) b[f] != Object.prototype[f] && (d += '<param name="' + f + '" value="' + b[f] + '" />');
i.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + l + ">" + d + "</object>";
F[F.length] = a.id;
g = k(a.id)
} else {
f = z.createElement(t);
f.setAttribute("type", y);
for (var n in a) a[n] != Object.prototype[n] && (n.toLowerCase() == "styleclass" ? f.setAttribute("class", a[n]) : n.toLowerCase() != "classid" && f.setAttribute(n, a[n]));
for (l in b) b[l] != Object.prototype[l] && l.toLowerCase() != "movie" && (a = f, d = l, n = b[l], c = z.createElement("param"), c.setAttribute("name", d), c.setAttribute("value", n), a.appendChild(c));
i.parentNode.replaceChild(f, i);
g = f
}
}
return g
}
function o(a) {
var b = k(a);
if (b && b.nodeName == "OBJECT") A.ie && A.win ? (b.style.display = "none", function() {
if (b.readyState == 4) {
var c = k(a);
if (c) {
for (var g in c) typeof c[g] == "function" && (c[g] = null);
c.parentNode.removeChild(c)
}
} else setTimeout(arguments.callee, 10)
}()) : b.parentNode.removeChild(b)
}
function k(a) {
var b = null;
try {
b = z.getElementById(a)
} catch (c) {}
return b
}
function p(a, b, c) {
a.attachEvent(b, c);
D[D.length] = [a, b, c]
}
function q(a) {
var b = A.pv,
a = a.split(".");
a[0] = parseInt(a[0], 10);
a[1] = parseInt(a[1], 10) || 0;
a[2] = parseInt(a[2], 10) || 0;
return b[0] > a[0] || b[0] == a[0] && b[1] > a[1] || b[0] == a[0] && b[1] == a[1] && b[2] >= a[2] ? !0 : !1
}
function s(a, b, c, g) {
if (!A.ie || !A.mac) {
var i = z.getElementsByTagName("head")[0];
if (i) {
c = c && typeof c == "string" ? c : "screen";
g && (P = K = null);
if (!K || P != c) g = z.createElement("style"), g.setAttribute("type", "text/css"), g.setAttribute("media", c), K = i.appendChild(g), A.ie && A.win && typeof z.styleSheets != v && z.styleSheets.length > 0 && (K = z.styleSheets[z.styleSheets.length - 1]), P = c;
A.ie && A.win ? K && typeof K.addRule == t && K.addRule(a, b) : K && typeof z.createTextNode != v && K.appendChild(z.createTextNode(a + " {" + b + "}"))
}
}
}
function u(a, b) {
if (Q) {
var c = b ? "visible" : "hidden";
L && k(a) ? k(a).style.visibility = c : s("#" + a, "visibility:" + c)
}
}
function w(a) {
return /[\\\"<>\.;]/.exec(a) != null && typeof encodeURIComponent != v ? encodeURIComponent(a) : a
}
var v = "undefined",
t = "object",
y = "application/x-shockwave-flash",
C = "SWFObjectExprInst",
x = window,
z = document,
B = navigator,
M = !1,
H = [function() {
M ? b() : c()
}],
E = [],
F = [],
D = [],
G, I, J, O, L = !1,
N = !1,
K, P, Q = !0,
A = function() {
var a = typeof z.getElementById != v && typeof z.getElementsByTagName != v && typeof z.createElement != v,
b = B.userAgent.toLowerCase(),
c = B.platform.toLowerCase(),
g = c ? /win/.test(c) : /win/.test(b),
c = c ? /mac/.test(c) : /mac/.test(b),
b = /webkit/.test(b) ? parseFloat(b.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : !1,
i = !+"\u000b1",
l = [0, 0, 0],
d = null;
if (typeof B.plugins != v && typeof B.plugins["Shockwave Flash"] == t) {
if ((d = B.plugins["Shockwave Flash"].description) && !(typeof B.mimeTypes != v && B.mimeTypes[y] && !B.mimeTypes[y].enabledPlugin)) M = !0, i = !1, d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1"), l[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10), l[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10), l[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0
} else if (typeof x.ActiveXObject != v) try {
var f = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
if (f && (d = f.GetVariable("$version"))) i = !0, d = d.split(" ")[1].split(","), l = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]
} catch (n) {}
return {
w3: a,
pv: l,
wk: b,
ie: i,
win: g,
mac: c
}
}();
(function() {
A.w3 && ((typeof z.readyState != v && z.readyState == "complete" || typeof z.readyState == v && (z.getElementsByTagName("body")[0] || z.body)) && d(), L || (typeof z.addEventListener != v && z.addEventListener("DOMContentLoaded", d, !1), A.ie && A.win && (z.attachEvent("onreadystatechange", function() {
z.readyState == "complete" && (z.detachEvent("onreadystatechange", arguments.callee), d())
}), x == top &&
function() {
if (!L) {
try {
z.documentElement.doScroll("left")
} catch (a) {
setTimeout(arguments.callee, 0);
return
}
d()
}
}()), A.wk &&
function() {
L || (/loaded|complete/.test(z.readyState) ? d() : setTimeout(arguments.callee, 0))
}(), f(d)))
})();
(function() {
A.ie && A.win && window.attachEvent("onunload", function() {
for (var a = D.length, b = 0; b < a; b++) D[b][0].detachEvent(D[b][1], D[b][2]);
a = F.length;
for (b = 0; b < a; b++) o(F[b]);
for (var c in A) A[c] = null;
A = null;
for (var g in swfobject) swfobject[g] = null;
swfobject = null
})
})();
return {
registerObject: function(a, b, c, g) {
if (A.w3 && a && b) {
var i = {};
i.id = a;
i.swfVersion = b;
i.expressInstall = c;
i.callbackFn =
g;
E[E.length] = i;
u(a, !1)
} else g && g({
success: !1,
id: a
})
},
getObjectById: function(b) {
if (A.w3) return a(b)
},
embedSWF: function(a, b, c, l, d, f, n, k, o, p) {
var y = {
success: !1,
id: b
};
A.w3 && !(A.wk && A.wk < 312) && a && b && c && l && d ? (u(b, !1), h(function() {
c += "";
l += "";
var h = {};
if (o && typeof o === t) for (var s in o) h[s] = o[s];
h.data = a;
h.width = c;
h.height = l;
s = {};
if (k && typeof k === t) for (var w in k) s[w] = k[w];
if (n && typeof n === t) for (var C in n) typeof s.flashvars != v ? s.flashvars += "&" + C + "=" + n[C] : s.flashvars = C + "=" + n[C];
if (q(d)) w = m(h, s, b), h.id == b && u(b, !0), y.success = !0, y.ref = w;
else if (f && g()) {
h.data = f;
i(h, s, b, p);
return
} else u(b, !0);
p && p(y)
})) : p && p(y)
},
switchOffAutoHideShow: function() {
Q = !1
},
ua: A,
getFlashPlayerVersion: function() {
return {
major: A.pv[0],
minor: A.pv[1],
release: A.pv[2]
}
},
hasFlashPlayerVersion: q,
createSWF: function(a, b, c) {
if (A.w3) return m(a, b, c)
},
showExpressInstall: function(a, b, c, l) {
A.w3 && g() && i(a, b, c, l)
},
removeSWF: function(a) {
A.w3 && o(a)
},
createCSS: function(a, b, c, g) {
A.w3 && s(a, b, c, g)
},
addDomLoadEvent: h,
addLoadEvent: f,
getQueryParamValue: function(a) {
var b =
z.location.search || z.location.hash;
if (b) {
/\?/.test(b) && (b = b.split("?")[1]);
if (a == null) return w(b);
for (var b = b.split("&"), c = 0; c < b.length; c++) if (b[c].substring(0, b[c].indexOf("=")) == a) return w(b[c].substring(b[c].indexOf("=") + 1))
}
return ""
},
expressInstallCallback: function() {
if (N) {
var a = k(C);
if (a && G) {
a.parentNode.replaceChild(G, a);
if (I && (u(I, !0), A.ie && A.win)) G.style.display = "block";
J && J(O)
}
N = !1
}
}
}
}(),
Spotify = Spotify || {};
Spotify.Cache = Spotify.Cache || {};
Spotify.Logging = Spotify.Logging || {};
Spotify.App = Spotify.App || {};
Spotify.Utils = Spotify.Utils || {};
Spotify.Flash = Spotify.Flash || {};
Spotify.Services = Spotify.Services || {};
Spotify.WebSockets = Spotify.WebSockets || {};
Spotify.Protobuf = Spotify.Protobuf || {};
Spotify.Hermes = Spotify.Hermes || {};
Spotify.Parsers = Spotify.Parsers || {};
Spotify.Models = Spotify.Models || {};
Spotify.HTML5 = Spotify.HTML5 || {};
Spotify.Proto = Spotify.Proto || {};
Spotify.Errors = Spotify.Errors || {};
Spotify.Errors.Domains = Spotify.Errors.Domains || {};
Spotify.Errors.Codes = Spotify.Errors.Codes || {};
DebuggerJS = Spotify.DebuggerJS = new
function() {
this.Parsers = {};
this.Loggers = {};
this.Parsers = {};
this.Utils = {
isArray: Array.isArray ||
function(d) {
return Object.prototype.toString.call(d) == "[object Array]"
}
};
var d = {},
h = {};
this.register = function(f, b, c) {
if (typeof f !== "string" || typeof b === "undefined" || b === null) throw Error("Not valid arguments");
d[f] || (d[f] = b);
h[f] || (h[f] = c || new DebuggerJS.Parsers.Console);
return !0
};
this.log = function() {};
this.warn = function() {};
this.error = function() {};
this.on = function(d, b) {
if (typeof d !== "undefined" && !DebuggerJS.Utils.isArray(d) && d !== null) throw Error("The modules argument should be an array");
if (typeof b !== "undefined" && !DebuggerJS.Utils.isArray(b) && b !== null) throw Error("The tags argument should be an array");
};
this.off = function() {}
};
DebuggerJS.Parsers.Default = function() {
this.parse = function(d, h, f) {
d += " |";
return [d].concat(h).concat("| Tag: " + f)
}
};
DebuggerJS.Loggers.Console = function() {
this.log = function() {
console.log.apply(console, arguments);
return !0
};
this.error = function() {
console.error.apply(console, arguments);
return !0
};
this.warn = function() {
console.warn.apply(console, arguments);
return !0
}
};
DebuggerJS.Loggers.Memory = function() {
this.log = function() {
return !0
};
this.error = function() {
return !0
};
this.warn = function() {
return !0
}
};
Spotify.Errors.Domains.HERMES_ERROR = 13;
Spotify.Errors.Domains.HERMES_SERVICE_ERROR = 14;
Spotify.Errors.Codes.HM_TOO_MANY_REQUESTS = 429;
Spotify.Errors.Codes.HM_TIMEOUT = 408;
Spotify.Errors.Codes.HM_FAILED_TO_SEND_TO_BACKEND = 1;
Spotify.Errors.Domains.TRACK_ERROR = 12;
Spotify.Errors.Codes.TRACK_REQUEST_RATE_LIMITED = 8;
Spotify.Errors.Error = function(d) {
d = d || [];
this.domain = d[0] || 0;
this.code = d[1] || 0;
this.description = d[2] || "";
this.data = d[3] || null
};
Spotify.RateLimiter = function(d, h) {
Spotify.EventTarget.call(this);
var f = this,
b = !1,
c = [],
a = new Spotify.Events,
g = 0;
this.totalPendingRequests = function() {
return c.length
};
this.getItemAtIndex = function(a) {
return c[a]
};
this.addToBucket = function(a, b) {
typeof b === "undefined" && (b = !0);
typeof a !== "undefined" && (b ? c.push(a) : c[0] = a)
};
this.start = function() {
b || (b = !0, clearInterval(g), g = setInterval(i, d))
};
var i = function() {
var i = 0,
l, d = h;
if (h > c.length) d = c.length;
for (; i < d; i++) l = c.shift(), f.trigger(a.RATE_LIMIT_CALL, l);
c.length === 0 && (b = !1, clearInterval(g), f.trigger(a.RATE_LIMIT_DISABLED))
}
};
Spotify.CallsManager = function() {
var d = 0,
h = {},
f = [0];
this.addCall = function(b, c, a, g, i, f, l, m) {
var o = (new Date).getTime();
d++;
h[d] = {
method: b,
params: c,
callback: a,
errback: g,
context: i,
persistent: f,
retries: typeof l === "undefined" ? 2 : l,
timestamp: o,
callType: m
};
return d
};
this.getCall = function(b, c) {
typeof c === "undefined" && (c = !0);
if (typeof h[b] !== void 0) {
var a = h[b];
c && delete h[b];
return a
}
};
this.getCalls = function() {
var b, c, a = [];
for (c in h) b = c, b = this.getCall(b), b.retries > 0 && a.push(b);
return a
};
this.getPersistentCalls =
function() {
for (var b = 0, c = f.length, a, g = []; b < c; b++) f[b] !== null && f[b] !== 0 && (a = f[b], g.push(this.getCall(a)));
f = [0];
return g
};
this.setPersistent = function(b, c) {
c === !0 ? f.push(b) : f[0] = b
}
};
Spotify.ConnectionManager = function() {
Spotify.EventTarget.call(this);
var d = this,
h = 0,
f, b = new Spotify.Events,
c, a = function() {
d.trigger(b.ON_TRY_TO_CONNECT)
},
g = function() {
h = 0;
typeof f !== "undefined" && clearTimeout(f)
};
this.reset = function() {
typeof f !== "undefined" && clearTimeout(f);
h = 0;
f = setTimeout(a, 0)
};
var i = function() {
var c = Math.pow(2, h) * 1E3;
h % 4 === 0 && h !== 0 && d.trigger(b.NOTIFY_OF_DISCONNECT);
c > 3E4 && (c = 3E4);
h++;
f && clearTimeout(f);
c === 1E3 && (c = 0);
f = setTimeout(a, c)
};
this.initialize = function(a) {
c = a;
c.bind(b.CONNECTION_ESTABLISHED, g, this);
c.bind(b.FAILED_CONNECTING, i, this)
}
};
Spotify.CodeValidator = function() {
Spotify.EventTarget.call(this);
var d = this,
h, f, b = new Spotify.Events,
c = function(a) {
eval(a.params)
},
a = function() {},
g = function() {};
this.reply = function() {
var b = Array.prototype.slice.call(arguments);
h.rpc("work_done", b, g, a, d, !1, 0, "work_done")
};
this.initialize = function(a, g) {
h = a;
f = g;
f.bind(b.WORK, c, this)
}
};
(function() {
Spotify.LinkedList = function() {
this.length = 0;
this.last = this.first = null
};
Spotify.LinkedList.prototype.append = function(d) {
if (d === null) throw Error("Node is null!");
if (d.list !== null) throw Error("Node already exists in another list!");
d.list = this;
this.first === null ? this.first = d : (d.prev = this.last, d.next = null, this.last.next = d);
this.last = d;
this.length++
};
Spotify.LinkedList.prototype.insertAfter = function(d, h) {
if (d === null || h === null) throw Error("Node is null!");
if (h.list !== null) throw Error("Node already exists in another list!");
h.list = this;
h.prev = d;
h.next = d.next;
d.next.prev = h;
d.next = h;
if (h.prev === this.last) this.last = h;
this.length++
};
Spotify.LinkedList.prototype.remove = function(d) {
if (d === null) throw Error("Node is null!");
if (this.length == 0 || d.list !== this) return !1;
else if (this.length > 1) {
if (d.prev !== null) d.prev.next = d.next;
if (d.next !== null) d.next.prev = d.prev;
if (d === this.first) this.first = d.next;
else if (d === this.last) this.last = d.prev
} else this.last = this.first = null;
delete d.list;
delete d.prev;
delete d.next;
d.list = null;
d.prev = null;
d.next = null;
this.length--;
return !0
};
Spotify.LinkedList.Node = function(d) {
this.next = this.prev = this.list = null;
this.value = d || null
}
})();
(function() {
Spotify.SimpleCache = function(d) {
this._limit = d || 100;
this._map = {};
this._lru = new Spotify.LinkedList;
this._stats = {
hits: 0,
misses: 0
}
};
Spotify.SimpleCache.prototype.get = function(d) {
if (d = this._map[d]) return this._lru.remove(d), this._lru.append(d), this._stats.hits++, d.value;
this._stats.misses++;
return null
};
Spotify.SimpleCache.prototype.put = function(d, h) {
if (typeof d == "undefined" || d == null || d == "") throw Error("Cache key can't be empty!");
this._lru.length >= this._limit && (delete this._map[this._lru.first.key], this._lru.remove(this._lru.first));
var f = this._map[d];
f ? (this._lru.remove(f), f.value = h) : (f = new Spotify.LinkedList.Node(h), f.key = d);
this._lru.append(f);
this._map[d] = f
};
Spotify.SimpleCache.prototype.remove = function(d) {
var h = this._map[d];
return h ? (this._lru.remove(h), delete this._map[d], h.value) : null
};
Spotify.SimpleCache.prototype.size = function() {
return this._lru.length
};
Spotify.SimpleCache.prototype.clear = function() {
this._lru = new Spotify.LinkedList;
this._map = {}
}
})();
Spotify.Cache.Default = function(d, h) {
this._limit = d || 100;
this._storage = h || new Spotify.Cache.MemoryStorage;
this._keyToNode = {};
this._lru = new Spotify.LinkedList;
this._stats = {
hits: 0,
misses: 0
};
this.initialize = function(d, b, c) {
if (!Spotify.Utils.isFunction(d) || !Spotify.Utils.isFunction(b)) throw new TypeError("Argument is not a function!");
var a = function(a, b) {
var c = new Spotify.LinkedList.Node(b);
c.key = a;
this._lru.append(c);
this._keyToNode[a] = c
},
g = function() {
d.call(c, this)
};
this._storage.initialize(function() {
this._storage.each(a, g, this)
}, b, this)
};
this.get = function(d, b, c) {
if (!Spotify.Utils.isFunction(b)) throw new TypeError("Argument is not a function!");
this._storage.get(d, function(a, g) {
var i = this._keyToNode[a] || null;
g !== null && i !== null ? (this._lru.remove(i), this._lru.append(i), this._stats.hits++, b.call(c, a, g)) : (this._stats.misses++, b.call(c, a, null))
}, this)
};
this.put = function(d, b, c, a, g, i) {
if (typeof d == "undefined" || d == null || d == "") throw Error("Cache key can't be empty!");
var n = function(d, f, h) {
if (f === null) if (Spotify.Utils.isFunction(g) && g.call(i, h), f = Math.floor(this._lru.length * 0.9), f == 0) a.call(i, d, null);
else {
for (; this._lru.length > f;) this._storage.remove(this._lru.first.key), this._lru.remove(this._lru.first);
this._storage.set(d, b, n, this)
} else Spotify.Utils.isFunction(c) && c.call(i, d, f)
};
this._lru.length >= this._limit && (this._storage.remove(this._lru.first.key), this._lru.remove(this._lru.first));
this._storage.get(d, function(a, c) {
var g = this._keyToNode[a] || null;
c !== null && g !== null ? (this._lru.remove(g), g.value = b) : (g = new Spotify.LinkedList.Node(b), g.key = a);
this._lru.append(g);
this._keyToNode[a] = g;
this._storage.set(a, b, n, this)
}, this)
};
this.remove = function(d, b, c) {
this._storage.get(d, function(a, g) {
var i = this._keyToNode[a] || null;
g !== null && i !== null ? (this._lru.remove(i), this._storage.remove(a, b, c)) : Spotify.Utils.isFunction(b) && b.call(c, a)
}, this)
};
this.size = function() {
return this._lru.length
};
this.clear = function(d, b) {
this._lru = new Spotify.LinkedList;
this._storage.clear(d, b)
}
};
Spotify.Cache.DummyStorage = function() {
this.initialize = function(d, h, f) {
if (!Spotify.Utils.isFunction(d) || !Spotify.Utils.isFunction(h)) throw new TypeError("Argument is not a function!");
h.call(f)
};
this.isSupported = function() {
return !0
}
};
Spotify.Cache.MemoryStorage = function() {
this._data = {};
this.get = function(d, h, f) {
if (!Spotify.Utils.isFunction(h)) throw new TypeError(ERROR_NOT_A_FUNCTION);
h.call(f, d, this._data[d] || null)
};
this.set = function(d, h, f, b) {
this._data[d] = h;
Spotify.Utils.isFunction(f) && f.call(b, d, h)
};
this.remove = function(d, h, f) {
delete this._data[d];
Spotify.Utils.isFunction(h) && h.call(f, d)
};
this.clear = function(d, h) {
this._data = {};
Spotify.Utils.isFunction(d) && d.call(h)
};
this.each = function(d, h, f) {
if (!Spotify.Utils.isFunction(d)) throw new TypeError(ERROR_NOT_A_FUNCTION);
var b = this._data,
c;
for (c in b) d.call(f, c, b[c]);
Spotify.Utils.isFunction(h) && h.call(f)
};
this.initialize = function(d, h, f) {
if (!Spotify.Utils.isFunction(d) || !Spotify.Utils.isFunction(h)) throw new TypeError(ERROR_NOT_A_FUNCTION);
d.call(f)
};
this.isSupported = function() {
return !0
}
};
Spotify.Cache.LocalStorage = function(d) {
this._prefix = "com.spotify.cache." + d + ".";
this.get = function(d, f, b) {
if (!Spotify.Utils.isFunction(f)) throw new TypeError("Argument is not a function!");
var c = window.localStorage.getItem(this._prefix + d);
f.call(b, d, c ? JSON.parse(c) : null)
};
this.set = function(d, f, b, c) {
try {
window.localStorage.setItem(this._prefix + d, JSON.stringify(f)), Spotify.Utils.isFunction(b) && b.call(c, d, f)
} catch (a) {
Spotify.Utils.isFunction(b) && b.call(c, d, null, a)
}
};
this.remove = function(d, f, b) {
window.localStorage.removeItem(this._prefix + d);
Spotify.Utils.isFunction(f) && f.call(b, d)
};
this.clear = function(d, f) {
for (var b = window.localStorage.length - 1; b >= 0; --b) {
var c = window.localStorage.key(b);
c.indexOf(this._prefix) == 0 && window.localStorage.removeItem(c)
}
Spotify.Utils.isFunction(d) && d.call(f)
};
this.each = function(d, f, b) {
if (!Spotify.Utils.isFunction(d)) throw new TypeError("Argument is not a function!");
for (var c = 0, a = window.localStorage.length; c < a; ++c) {
var g = window.localStorage.key(c);
if (g.indexOf(this._prefix) == 0) {
var i = window.localStorage.getItem(g);
d.call(b, g.slice(this._prefix.length), i ? JSON.parse(i) : null)
}
}
Spotify.Utils.isFunction(f) && f.call(b)
};
this.initialize = function(d, f, b) {
if (!Spotify.Utils.isFunction(d) || !Spotify.Utils.isFunction(f)) throw new TypeError("Argument is not a function!");
d.call(b)
};
this.isSupported = function() {
return typeof window.localStorage !== "undefined"
}
};
Spotify.Cache.IndexedDBStorage = function(d) {
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
var h = null,
f = function(b, a, g, i, d) {
var l = window.indexedDB.open(b, a);
l.onsuccess = function(l) {
var f = l.target.result;
Spotify.Utils.isFunction(f.setVersion) ? (l = parseInt(f.version || "0", 10), l < a ? (l = f.setVersion(a.toString()), l.onsuccess =
function() {
f.objectStoreNames.contains(b) || f.createObjectStore(b);
g.call(d, f)
}, l.onerror = function() {
i.call(d)
}) : l == a ? g.call(d, f) : i.call(d)) : g.call(d, f)
};
l.onerror = function() {
i.call()
};
l.onupgradeneeded = function(a) {
a = a.target.result;
a.objectStoreNames.contains(b) || a.createObjectStore(b)
}
},
b = function(b, a) {
return function(g) {
h = g;
b.call(a)
}
};
this._open = function(c, a, g) {
f(d, 1, b(c, g), a)
};
this._transaction = function(b) {
return h.transaction(d, b).objectStore(d)
};
this.get = function(b, a, g) {
if (!Spotify.Utils.isFunction(a)) throw new TypeError(ERROR_NOT_A_FUNCTION);
var i = this._transaction(IDBTransaction.READ_ONLY).get(b);
i.onsuccess = function(i) {
a.call(g, b, i.target.result)
};
i.onerror = function(i) {
a.call(g, b, null, i.target.errorCode)
}
};
this.set = function(b, a, g, i) {
var d = this._transaction(IDBTransaction.READ_WRITE).put(a, b);
if (Spotify.Utils.isFunction(g)) d.onsuccess = function() {
g.call(i, b, a)
}, d.onerror = function(a) {
g.call(i, b, null, a.target.errorCode)
}
};
this.remove = function(b, a, g) {
var i = this._transaction(IDBTransaction.READ_WRITE)["delete"](b);
if (Spotify.Utils.isFunction(a)) i.onsuccess =
function() {
a.call(g, b)
}, i.onerror = function() {
a.call(g, null, e.target.errorCode)
}
};
this.clear = function(b, a) {
var g = this._transaction(IDBTransaction.READ_WRITE).clear();
if (Spotify.Utils.isFunction(b)) g.onsuccess = function() {
b.call(a)
}, g.onerror = function() {
b.call(a)
}
};
this.each = function(b, a, g) {
if (!Spotify.Utils.isFunction(b)) throw new TypeError(ERROR_NOT_A_FUNCTION);
this._transaction(IDBTransaction.READ_ONLY).openCursor().onsuccess = function(i) {
(i = i.target.result) ? (b.call(g, i.key, i.value), i["continue"]()) : Spotify.Utils.isFunction(a) && a.call(g)
}
};
this.initialize = function(b, a, g) {
if (!Spotify.Utils.isFunction(b) || !Spotify.Utils.isFunction(a)) throw new TypeError(ERROR_NOT_A_FUNCTION);
this._open(b, a, g)
};
this.isSupported = function() {
return typeof window.indexedDB !== "undefined" || typeof window.mozIndexedDB !== "undefined" || typeof window.webkitIndexedDB !== "undefined" || typeof window.msIndexedDB !== "undefined"
}
};
Spotify.Cache.FileSystemStorage = function() {
throw Error("Not implemented!");
};
(function() {
var d;
Spotify.Events = function() {
return typeof d !== "undefined" ? d : d = {
DATA_ERROR: "DATA_ERROR",
TRACK_PLAY_REQUEST: "TRACK_PLAY_REQUEST",
WAIT_FOR_COMMERCIAL_TO_FINISH: "WAIT_FOR_COMMERCIAL_TO_FINISH",
INTERCEPTED: "intercepted",
USER_INFO_CHANGE: "USER_INFO_CHANGE",
TRACK_ENDED: "TRACK_ENDED",
ON_LOAD: "ON_LOAD",
SONG_LOADED: "SONG_LOADED",
FIRST_BYTES: "FIRST_BYTES",
POSITION_CHANGED: "POSITION_CHANGED",
VOLUME_CHANGED: "VOLUME_CHANGED",
PLAYING: "PLAYING",
PAUSED: "PAUSED",
STOPPED: "STOPPED",
CONNECTION_ESTABLISHED: "CONNECTION_ESTABLISHED",
CONNECTION_CLOSED: "CONNECTION_CLOSED",
CONNECTED: "CONNECTED",
DISCONNECTED: "DISCONNECTED",
STREAM_INITIALIZED: "STREAM_INITIALIZED",
PLAYER_LOADED: "PLAYER_LOADED",
STREAM_LIMIT_REACHED: "STREAM_LIMIT_REACHED",
AUTHENTICATED: "AUTHENTICATED",
ERROR: "ERROR",
SUCCESS: "SUCCESS",
FAILED_CONNECTING: "FAILED_CONNECTING",
INVALID_TRACK_URI: "INVALID_TRACK_URI",
CANNOT_PLAY_TRACK: "CANNOT_PLAY_TRACK",
INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
REGION_BLOCKED: "REGION_BLOCKED",
ACCOUNT_IN_USE: "ACCOUNT_IN_USE",
PLAYBACK_FAILED: "PLAYBACK_FAILED",
SECURITY_ERROR: "SECURITY_ERROR",
UNKNOWN_ERROR: "UNKNOWN_ERROR",
RPC_CALLBACK: "RPC_CALLBACK",
RPC_ERRBACK: "RPC_ERRBACK",
RPC_LOGGING_LATENCY_CALLBACK: "RPC_LOGGING_LATENCY_CALLBACK",
RPC_LOGGING_LATENCY_ERRBACK: "RPC_LOGGING_LATENCY_ERRBACK",
RPC_SUCCESS: "RPC_SUCCESS",
RPC_ERROR: "RPC_ERROR",
REAUTHORIZE_SUCCESS: "REAUTHORIZE_SUCCESS",
REAUTHORIZE_FAILED: "REAUTHORIZE_FAILED",
FLASH_LOADED: "FLASH_LOADED",
FLASH_UNAVAILABLE: "FLASH_UNAVAILABLE",
FLASH_AVAILABLE: "FLASH_AVAILABLE",
READY: "READY",
TOKEN_ACQUIRED: "TOKEN_ACQUIRED",
TOKEN_NOT_ACQUIRED: "TOKEN_NOT_ACQUIRED",
ON_TRY_TO_CONNECT: "ON_TRY_TO_CONNECT",
NOTIFY_OF_DISCONNECT: "NOTIFY_OF_DISCONNECT",
FATAL_ERROR: "FATAL_ERROR",
TOKEN_LOST: "TOKEN_LOST",
WORK: "WORK",
LOGIN_COMPLETE: "LOGIN_COMPLETE",
HERMES_B64_MESSAGE: "HERMES_B64_MESSAGE",
TIMEOUT: "TIMEOUT",
NO_SOUND_CAPABILITIES: "NO_SOUND_CAPABILITIES",
ON_REAUTHENTICATION_SUCCESS: "ON_REAUTHENTICATION_SUCCESS",
ON_REAUTHENTICATION_FAILED: "ON_REAUTHENTICATION_FAILED",
STORAGE_FULL: "STORAGE_FULL",
RATE_LIMIT_CALL: "RATE_LIMIT_CALL",
RATE_LIMIT_DISABLED: "RATE_LIMIT_DISABLED",
REMOTE_CONTROL_STARTED: "REMOTE_CONTROL_STARTED",
REMOTE_CONTROL_STOPPED: "REMOTE_CONTROL_STOPPED",
DEVICE_DISCOVERED: "DEVICE_DISCOVERED",
DEVICE_REMOVED: "DEVICE_REMOVED",
REMOTE_COMMAND: "REMOTE_COMMAND",
REMOTE_SERVICE_DOWN: "REMOTE_SERVICE_DOWN",
NOTIFICATION: "NOTIFICATION",
RELATIONS_SUBSCRIBE: "RELATIONS_SUBSCRIBE",
RELATIONS_UNSUBSCRIBE: "RELATIONS_UNSUBSCRIBE"
}
}
})();
Spotify.Ajax = function(d) {
var h = Spotify.DebuggerJS,
d = d || {},
f = {};
f.method = d.method || "GET";
f.dataType = d.dataType || "text";
f.url = d.url || void 0;
f.data = d.data || "";
f.async = d.async !== void 0 ? d.async : !0;
f.success = d.success || void 0;
f.error = d.error || void 0;
f.context = d.context || void 0;
this.POST = "POST";
this.GET = "GET";
this.JSON = "json";
this.XML = "xml";
this.TEXT = "text";
this.execute = function() {
var b, c = f.url,
a = "",
g, i = function(a) {
f.context !== void 0 ? f.error.call(f.context, a) : f.error(a)
},
d = function() {
if (typeof f.success !== "undefined") {
if (f.dataType === "xml") try {
g = b.responseXML || Spotify.Utils.convertStringToXML(b.responseText)
} catch (a) {
i(a)
}
if (f.dataType === "json") try {
g = JSON.parse(b.responseText)
} catch (c) {
i(c)
}
f.dataType === "text" && (g = b.responseText);
f.context !== void 0 ? f.success.call(f.context, g, b) : f.success(g, b)
}
},
l = function() {
typeof f.error !== "undefined" && i()
},
m = function() {
d()
},
o = function(a) {
l(a)
};
b = XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject("Microsoft.XMLHTTP");
f.method === this.POST ? a = f.data : c += f.data !== "" ? "?" + f.data : "";
try {
try {
b.open(f.method, c, f.async)
} catch (k) {
if (XDomainRequest) h.log("Spotify.Ajax", ["Trying Cors"], "corejs"), b = new XDomainRequest, b.onprogress = function() {}, b.onload = m, b.onerror = o, b.open(f.method, c, f.async);
else
throw Error("CORS not supported");
}
b.send(a)
} catch (p) {
h.error("Spotify.Ajax", [p], "corejs"), i(p)
}
b.onreadystatechange = function() {
b.readyState === 4 && b.status >= 200 && b.status < 300 ? d() : b.status >= 400 && l()
};
return b
}
};
Spotify.Service = function() {
Spotify.EventTarget.call(this);
this.url = "";
this.method = "GET";
this.dataType = "text";
this.data = "";
this.async = !0;
this.fetch = function() {
(new Spotify.Ajax({
method: this.method,
dataType: this.dataType,
url: this.url,
data: this.data,
success: d,
error: h,
context: this
})).execute()
};
var d = function(d, b) {
this.trigger("onSuccess", {
result: d,
request: b
})
},
h = function(d) {
this.trigger("onError", {
error: d
})
}
};
Spotify.Proto.Data = function(d, h) {
Spotify.EventTarget.call(this);
var f = this,
b, c = {},
a = new Spotify.Events;
this.initialize = function() {
var a = new Spotify.Service;
a.url = d + "data.xml" + h;
a.async = !1;
a.dataType = "text";
a.bind("onSuccess", g, this);
a.bind("onError", i, this);
a.fetch()
};
this.getDefinition = function(a) {
if (typeof c[a] !== "undefined") return c[a];
var g = b.getElementsByTagName(a);
return typeof g !== "undefined" && g[0] && g[0].firstChild ? (c[a] = g[0].firstChild.data + "\n", c[a]) : ""
};
this.getMultipleDefinitions = function(a) {
var g = "",
i = 0,
d, f;
if (!Spotify.Utils.isArray(a)) throw Error("Definition identifiers must be an array with strings");
for (; i < a.length; i++) {
f = a[i];
if (typeof c[f] !== "undefined") {
g += c[f];
break
}
d = b.getElementsByTagName(f);
typeof d !== "undefined" && d[0] && d[0].firstChild && (c[f] = d[0].firstChild.data + "\n", g += c[f])
}
return g
};
var g = function(c) {
b = Spotify.Utils.convertStringToXML(c.params.result);
f.trigger(a.SUCCESS)
},
i = function(b) {
f.trigger(a.ERROR, b.params)
}
};
Spotify.Core = function(d, h, f) {
Spotify.EventTarget.call(this);
Spotify.DebuggerJS.register("console", new Spotify.DebuggerJS.Loggers.Console, new Spotify.DebuggerJS.Parsers.Default);
var b = this,
c = Spotify.DebuggerJS,
a = !1,
g = {
playerType: h,
SWFContainerId: f.SWFContainerId || "",
SWFUrl: f.SWFUrl || "bridge.swf",
SWFMinVersion: f.SWFMinVersion || "10.2.0",
connectionUri: f.connectionUri || [],
logging: f.logging || 0,
length: f.length || 0,
valid: f.valid || 0,
cdn: f.cdn || "",
authUrl: f.authUrl || "",
protoSchemasLocation: f.protoSchemasLocation || "proto/",
protoSchemasLocationRandomizer: f.protoSchemasLocationRandomizer || ""
};
this.id = "";
var i = d || Spotify.GatewayTypes.FLASH,
n = h || Spotify.PlayerTypes.RTMPS,
l, m = new Spotify.Events,
o;
this.songUriResolver = this._bridge = this.mergedProfile = this.adChooser = this.presence = this.hermes = this.socialGraph = this.social = this.toplist = this.user = this.search = this.popcount = this.appstore = this.playlist = this.metadata = this.pubsub = this.suggest = this.player = null;
this.logging = {};
this.isReady = !1;
this.onConnect = function() {};
this.onDisconnect =
function() {};
this.onReady = function() {};
this.onTokenLost = function() {};
this.connect = function(a) {
l.connect(a)
};
this.reauthenticate = function(a) {
l.reauthenticate(a)
};
this.disconnect = function() {
l.disconnect()
};
this.migrateToIndexedDBStorage = function(a, b, c) {
Spotify.Hermes.Cache.migrateToIndexedDB(a, b, c)
};
this.initialize = function() {
o = new Spotify.Proto.Data(g.protoSchemasLocation, g.protoSchemasLocationRandomizer);
o.bind(m.SUCCESS, k);
o.bind(m.ERROR, s);
o.initialize()
};
this.dispose = function() {
l.dispose()
};
var k =
function() {
Spotify.Instances.add(b);
l = new Spotify.Gateway(i, n);
l.bind(m.READY, y, b);
l.bind(m.ON_TRY_TO_CONNECT, C, b);
l.bind(m.CONNECTED, v, b);
l.bind(m.DISCONNECTED, b.onDisconnect, b);
l.bind(m.TOKEN_LOST, b.onTokenLost, b);
l.bind(m.USER_INFO_CHANGE, p, b);
l.bind(m.FLASH_AVAILABLE, q, b);
l.bind(m.FLASH_UNAVAILABLE, q, b);
Spotify.Hermes.Cache.onfull = w;
(new Spotify.Heartbeat(l)).initialize();
l.initialize(b.id, g);
b._bridge = l.bridge;
b.player = l.player;
b.player.bind(m.NO_SOUND_CAPABILITIES, u)
},
p = function() {
b.trigger(m.USER_INFO_CHANGE)
},
q = function(a) {
a.type === m.UNAVAILABLE ? b.trigger(m.FLASH_UNAVAILABLE) : setTimeout(function() {
b.isReady ? c.log("Spotify.Core", ["Flash is available"], "corejs") : (c.error("Spotify.Core", ["Flash is NOT available"], "corejs"), b.trigger(m.FLASH_UNAVAILABLE))
}, 5E3)
},
s = function(a) {
b.trigger(m.DATA_ERROR, a)
},
u = function() {
b.trigger(m.NO_SOUND_CAPABILITIES)
},
w = function() {
b.trigger(m.STORAGE_FULL)
},
v = function(c) {
if (!a) a = !0, b.user = new Spotify.Services.User, b.user.init(l), b.appstore = new Spotify.Services.AppStore(o.getDefinition("appstore")), b.appstore.init(l), b.popcount = new Spotify.Services.PopCount(o.getDefinition("popcount")), b.popcount.init(l), b.metadata = new Spotify.Services.Metadata(o.getMultipleDefinitions(["metadata", "mercury"])), b.metadata.init(l, b.user), b.search = new Spotify.Services.Search, b.search.init(l, b.user), b.suggest = new Spotify.Services.Suggest(o.getDefinition("suggest")), b.suggest.init(l, b.user), b.pubsub = new Spotify.Services.Pubsub(o.getDefinition("pubsub")), b.pubsub.init(l), b.toplist = new Spotify.Services.Toplist(o.getMultipleDefinitions(["toplist", "socialgraph"])), b.toplist.init(l, b.user), b.playlist = new Spotify.Services.Playlist(o.getMultipleDefinitions("playlist4changes,playlist4content,playlist4issues,playlist4meta,playlist4ops,playlist4service".split(","))), b.playlist.init(l, b.user), b.social = new Spotify.Services.Social(o.getMultipleDefinitions(["social", "mercury"])), b.social.init(l), b.presence = new Spotify.Services.Presence(o.getDefinition("presence")), b.presence.init(l, b.pubsub, b.user), b.socialGraph = new Spotify.Services.SocialGraph(o.getMultipleDefinitions(["socialgraph"])), b.socialGraph.init(l, b.user), b.player.songUriResolver = new Spotify.Services.SongUriResolver, b.player.songUriResolver.init(l), b.player.adUriResolver = new Spotify.Services.AdUriResolver, b.player.adUriResolver.init(l), b.hermes = new Spotify.Hermes.Handler, b.hermes.init(l), b.logging.clientEvent = new Spotify.Logging.ClientEvent, b.logging.clientEvent.init(l), b.logging.logger = new Spotify.Logging.Logger, b.logging.logger.init(l), b.logging.view = new Spotify.Logging.View, b.logging.view.init(l), b.logging.endSong = {
setEndSongStopLog: l.playerTracker.setEndSongStopLog,
setEndSongStartLog: l.playerTracker.setEndSongStartLog
}, b.contextManager = new Spotify.App.ContextManager, b.contextPlayer = new Spotify.App.ContextPlayer(b), b.contextPlayer.addEvent(m.INTERCEPTED, t), b.adChooser = new Spotify.Services.AdChooser, b.adChooser.init(l, b.contextManager, b.contextPlayer, b.player, b.user), l.playerTracker.setAdService(b.adChooser), b.mergedProfile = new Spotify.Services.MergedProfile(o.getDefinition("mergedprofile")), b.mergedProfile.init(l);
b.onConnect(c)
},
t = function() {
b.trigger(m.WAIT_FOR_COMMERCIAL_TO_FINISH)
},
y = function(a) {
setTimeout(function() {
b.isReady = !0;
b.onReady(a);
b.trigger(m.ON_TRY_TO_CONNECT)
}, 1)
},
C = function() {
b.trigger(m.ON_TRY_TO_CONNECT)
}
};
(function() {
Spotify.Link = function(a, b) {
this.type = a;
for (var c in b) this[c] = b[c]
};
var d = Spotify.Link;
d.Type = {
EMPTY: "empty",
ALBUM: "album",
AD: "ad",
APPLICATION: "application",
ARTIST: "artist",
ARTIST_TOPLIST: "artist-toplist",
CONTEXT_GROUP: "context-group",
FACEBOOK: "facebook",
FOLLOWERS: "followers",
FOLLOWING: "following",
IMAGE: "image",
INBOX: "inbox",
LOCAL: "local",
LIBRARY: "library",
MOSAIC: "mosaic",
PLAYLIST: "playlist",
PROFILE: "profile",
PUBLISHED_ROOTLIST: "published-rootlist",
RADIO: "radio",
ROOTLIST: "rootlist",
COLLECTION_TRACK_LIST: "collectiontracklist",
SEARCH: "search",
STARRED: "starred",
TEMP_PLAYLIST: "temp-playlist",
TOPLIST: "toplist",
TRACK: "track",
USER_TOPLIST: "user-toplist",
USET_TOP_TRACKS: "user-top-tracks"
};
var h = function(a, b) {
var c, d = 1;
if (a.indexOf("spotify:") == 0) c = a.slice(8).split(":"), d = 0;
else if (a.indexOf("http://play.spotify.com/") == 0) c = a.slice(24).split("/");
else if (a.indexOf("https://play.spotify.com/") == 0) c = a.slice(25).split("/");
else if (a.indexOf("http://open.spotify.com/") == 0) c = a.slice(24).split("/");
else if (a.indexOf("https://open.spotify.com/") == 0) c = a.slice(25).split("/");
else
throw "Invalid Spotify URI!";
Array.prototype.push.apply(b, c);
return d
},
f = function(a, b) {
a = encodeURIComponent(a);
return b == 0 ? a.replace(/%20/g, "+") : a
},
b = function(a, b) {
return decodeURIComponent(b == 0 ? a.replace(/\+/g, "%20") : a)
},
c = function(a, b) {
var c;
a.id && (c = Spotify.Utils.Base62.fromHex(a.id, 22));
switch (a.type) {
case d.Type.ALBUM:
return c = ["album", c], a.disc && c.push(a.disc), c;
case d.Type.AD:
return ["ad", a.id];
case d.Type.ARTIST:
return ["artist", c];
case d.Type.ARTIST_TOPLIST:
return ["artist", c, "top", a.toplist];
case d.Type.SEARCH:
return ["search", f(a.query, b)];
case d.Type.TRACK:
return ["track", c];
case d.Type.FACEBOOK:
return ["user", "facebook", a.uid];
case d.Type.FOLLOWERS:
return ["user", a.username, "followers"];
case d.Type.FOLLOWING:
return ["user", a.username, "following"];
case d.Type.PLAYLIST:
return ["user", a.username, "playlist", c];
case d.Type.STARRED:
return ["user", a.username, "starred"];
case d.Type.TEMP_PLAYLIST:
return ["temp-playlist", a.origin, a.data];
case d.Type.CONTEXT_GROUP:
return ["context-group", a.origin, a.name];
case d.Type.USER_TOPLIST:
return ["user", a.username, "top", a.toplist];
case d.Type.USET_TOP_TRACKS:
return ["user", a.username, "toplist"];
case d.Type.TOPLIST:
return ["top", a.toplist].concat(a.global ? ["global"] : ["country", a.country]);
case d.Type.INBOX:
return ["user", a.username, "inbox"];
case d.Type.ROOTLIST:
return ["user", a.username, "rootlist"];
case d.Type.PUBLISHED_ROOTLIST:
return ["user", a.username, "publishedrootlist"];
case d.Type.COLLECTION_TRACK_LIST:
return ["user", a.username, "collectiontracklist", c];
case d.Type.PROFILE:
return ["user", a.username];
case d.Type.LOCAL:
return ["local", f(a.artist, b), f(a.album, b), f(a.track, b), a.duration];
case d.Type.LIBRARY:
return ["user", a.username, "library", a.category];
case d.Type.IMAGE:
return ["image", a.id];
case d.Type.MOSAIC:
return c = a.ids.slice(0), c.unshift("mosaic"), c;
case d.Type.RADIO:
return ["radio", a.args];
case d.Type.APPLICATION:
c = ["app", a.id];
for (var n = a.args || [], l = 0, h = n.length; l < h; ++l) c.push(f(n[l], b));
return c;
default:
throw "Invalid Spotify URI!";
}
};
d.prototype.toURI =
function() {
return "spotify:" + c(this, 0).join(":")
};
d.prototype.toAppLink = function() {
if (this.type == d.Type.APPLICATION) return d.applicationLink(this.id, this.args);
else {
var a = c(this, 1),
g = a.shift();
a.length && (a = a.map(function(a) {
return b(a, 1)
}));
return d.applicationLink(g, this.type == d.Type.RADIO ? a.shift().split(":") : a)
}
};
d.prototype.toAppURI = function() {
return this.type == d.Type.APPLICATION ? this.toURI() : "spotify:" + ["app"].concat(c(this, 0)).join(":")
};
d.prototype.toURLPath = function() {
var a = c(this, 1);
a[0] === "app" && a.shift();
return a.join("/")
};
d.prototype.toURL = function(a) {
typeof a === "undefined" && (a = !0);
return a ? "http://play.spotify.com/" + this.toURLPath() : "/" + this.toURLPath()
};
d.prototype.toSecureURL = function() {
return "https://play.spotify.com/" + this.toURLPath()
};
d.prototype.toString = function() {
return this.toURI()
};
d.fromString = function(a) {
var c = [],
i = h(a, c),
f = 0,
l = function() {
return c[f++]
},
a = function() {
var a = l();
return a.length == 22 ? Spotify.Utils.Base62.toHex(a, 32) : a
},
m = function() {
return c.slice(f).join(i == 0 ? ":" : "/")
},
o = l();
switch (o) {
case "album":
return d.albumLink(a(), parseInt(l(), 10));
case "ad":
return d.adLink(a());
case "artist":
return a = a(), l() == "top" ? d.artistToplistLink(a, l()) : d.artistLink(a);
case "temp-playlist":
return d.temporaryPlaylistLink(l(), m());
case "search":
return d.searchLink(b(m(), i));
case "track":
return d.trackLink(a());
case "trackset":
throw "Not implemented!";
case "context-group":
return d.contextGroupLink(l(), l());
case "top":
return a = l(), l() == "global" ? d.toplistLink(a, null, !0) : d.toplistLink(a, l(), !1);
case "user":
m = l();
o = l();
if (m == "facebook" && o != null) return d.facebookLink(parseInt(o, 10));
else if (o != null) switch (o) {
case "playlist":
return d.playlistLink(m, a());
case "collectiontracklist":
return d.collectionTrackList(m, a());
case "starred":
return d.starredLink(m);
case "followers":
return d.followersLink(m);
case "following":
return d.followingLink(m);
case "top":
return d.userToplistLink(m, l());
case "inbox":
return d.inboxLink(m);
case "rootlist":
return d.rootlistLink(m);
case "publishedrootlist":
return d.publishedRootlistLink(m);
case "toplist":
return d.userTopTracksLink(m);
case "library":
return d.libraryLink(m, l())
}
return d.profileLink(m);
case "local":
return d.localLink(b(l(), i), b(l(), i), b(l(), i), parseInt(l(), 10));
case "image":
return d.imageLink(a());
case "mosaic":
return d.mosaicLink(c.slice(f));
case "radio":
return d.radioLink(m());
default:
for (var a = o === "app" ? l() : o, m = c.slice(f), o = 0, k = m.length; o < k; ++o) m[o] = b(m[o], i);
return d.applicationLink(a, m)
}
throw "Invalid Spotify URI!";
};
d.emptyLink = function() {
return new d(d.Type.EMPTY, {})
};
d.albumLink = function(a, b) {
return new d(d.Type.ALBUM, {
id: a,
disc: b
})
};
d.adLink = function(a) {
return new d(d.Type.AD, {
id: a
})
};
d.artistLink = function(a) {
return new d(d.Type.ARTIST, {
id: a
})
};
d.artistToplistLink = function(a, b) {
return new d(d.Type.ARTIST_TOPLIST, {
id: a,
toplist: b
})
};
d.searchLink = function(a) {
return new d(d.Type.SEARCH, {
query: a
})
};
d.trackLink = function(a) {
return new d(d.Type.TRACK, {
id: a
})
};
d.facebookLink = function(a) {
return new d(d.Type.FACEBOOK, {
uid: a
})
};
d.followersLink = function(a) {
return new d(d.Type.FOLLOWERS, {
username: a
})
};
d.followingLink = function(a) {
return new d(d.Type.FOLLOWING, {
username: a
})
};
d.playlistLink = function(a, b) {
return new d(d.Type.PLAYLIST, {
username: a,
id: b
})
};
d.collectionTrackList = function(a, b) {
return new d(d.Type.COLLECTION_TRACK_LIST, {
username: a,
id: b
})
};
d.starredLink = function(a) {
return new d(d.Type.STARRED, {
username: a
})
};
d.userToplistLink = function(a, b) {
return new d(d.Type.USER_TOPLIST, {
username: a,
toplist: b
})
};
d.userTopTracksLink = function(a) {
return new d(d.Type.USET_TOP_TRACKS, {
username: a
})
};
d.toplistLink = function(a, b, c) {
return new d(d.Type.TOPLIST, {
toplist: a,
country: b,
global: !! c
})
};
d.inboxLink = function(a) {
return new d(d.Type.INBOX, {
username: a
})
};
d.rootlistLink = function(a) {
return new d(d.Type.ROOTLIST, {
username: a
})
};
d.publishedRootlistLink = function(a) {
return new d(d.Type.PUBLISHED_ROOTLIST, {
username: a
})
};
d.localLink = function(a, b, c, f) {
return new d(d.Type.LOCAL, {
artist: a,
album: b,
track: c,
duration: f
})
};
d.libraryLink = function(a, b) {
return new d(d.Type.LIBRARY, {
username: a,
category: b
})
};
d.temporaryPlaylistLink =
function(a, b) {
return new d(d.Type.TEMP_PLAYLIST, {
origin: a,
data: b
})
};
d.contextGroupLink = function(a, b) {
return new d(d.Type.CONTEXT_GROUP, {
origin: a,
name: b
})
};
d.profileLink = function(a) {
return new d(d.Type.PROFILE, {
username: a
})
};
d.imageLink = function(a) {
return new d(d.Type.IMAGE, {
id: a
})
};
d.mosaicLink = function(a) {
return new d(d.Type.MOSAIC, {
ids: a
})
};
d.radioLink = function(a) {
a = typeof a === "undefined" ? [] : a;
return new d(d.Type.RADIO, {
args: a
})
};
d.applicationLink = function(a, b) {
b = typeof b === "undefined" ? [] : b;
return new d(d.Type.APPLICATION, {
id: a,
args: b
})
}
})();
(function() {
var d;
Spotify.Logging.Types = function() {
return typeof d !== "undefined" ? d : d = {
TRACK_END: "TRACK_END",
TRACK_EVENT: "TRACK_EVENT",
TRACK_PROGRESS: "TRACK_PROGRESS",
REQUEST_TIME: "REQUEST_TIME",
AD_END: "EndAd"
}
}
})();
Spotify.Logging.TrackEnd = function() {
Spotify.EventTarget.call(this);
var d, h = function() {},
f = function() {};
this.serviceIsReady = !0;
this.log = function(b) {
d.rpc("track_end", [b.lid, b.ms_played, b.ms_played_union, b.n_seeks_forward, b.n_seeks_backward, b.ms_seeks_forward, b.ms_seeks_backward, b.ms_latency, b.display_track, b.play_context, b.source_start, b.source_end, b.reason_start, b.reason_end, b.referrer, b.referrer_version, b.referrer_vendor, b.max_continuous], h, f, this, !0, 2, "track_end")
};
this.init = function(b) {
d = b
}
};
Spotify.Logging.TrackEvent = function() {
Spotify.EventTarget.call(this);
var d, h = function() {},
f = function() {};
this.serviceIsReady = !0;
this.log = function(b) {
d.rpc("track_event", [b.lid, b.event, b.ms_where], h, f, this, !0, 2, "track_event")
};
this.init = function(b) {
d = b
}
};
Spotify.Logging.TrackProgress = function() {
Spotify.EventTarget.call(this);
var d = Spotify.DebuggerJS,
h, f = function(b) {
d.log("Spotify.Logging.TrackProgress", ["Track progress success", b], "corejs")
},
b = function(b) {
d.error("Spotify.Logging.TrackProgress", ["On track progress error", b], "corejs")
};
this.serviceIsReady = !0;
this.log = function(c) {
h.rpc("track_progress", [c.lid, c.source_start, c.reason_start, c.ms_played, c.ms_latency, c.play_context, c.display_track, c.referrer, c.referrer_version, c.referrer_vendor], f, b, this, !0, 2, "track_progress")
};
this.init = function(b) {
h = b
}
};
Spotify.Logging.ClientEvent = function() {
Spotify.EventTarget.call(this);
var d, h = function() {},
f = function() {};
this.serviceIsReady = !0;
this.log = function(b) {
if (typeof b.source !== "string") throw Error("Source must be a string");
if (typeof b.context !== "string") b.context = "";
if (typeof b.event !== "string") throw Error("Event name must be a string");
if (typeof b.event_version !== "string") b.event_version = "";
if (typeof b.test_version !== "string") b.test_version = "";
if (typeof b.source_version !== "string") throw Error("Source version name must be a string");
if (typeof b.source_vendor !== "string") throw Error("Source vendor name must be a string");
if (typeof b.data !== "string") b.data = "";
d.rpc("log_ce", [b.source, b.context, b.event, b.event_version, b.test_version, b.source_version, b.source_vendor, b.data], h, f, this, !0, 2, "log_ce")
};
this.init = function(b) {
d = b
}
};
Spotify.Logging.AdEnd = function() {
Spotify.EventTarget.call(this);
var d, h = function() {},
f = function() {};
this.serviceIsReady = !0;
this.log = function(b) {
d.rpc("log_ad", [String(b.file_id), String(b.ad_file_id), String(b.lid), String(b.source_start), String(b.reason_start), String(b.source_end), String(b.reason_end), String(b.bytes_played), String(b.content_length), String(b.ms_played), String(b.ms_played_union), String(b.ms_rcv_latency), String(b.n_seeks_backward), String(b.ms_seeks_backward), String(b.n_seeks_forward), String(b.ms_seeks_forward), String(b.ms_latency), String(b.num_stutter), String(b.p_lowbuffer), String(b.skipped), String(b.clicked), String(b.token), String(b.last_stream_started_at), String(b["client-ad-count"]), String(b["client-campaign-count"])], h, f, this, !0, 2, "log_ad")
};
this.init = function(b) {
d = b
}
};
Spotify.Logging.View = function() {
Spotify.EventTarget.call(this);
var d, h = function() {},
f = function() {};
this.serviceIsReady = !0;
this.log = function(b, c, a, g) {
if (typeof b !== "string") throw Error("Uri must be a string");
if (typeof c !== "string") throw Error("View version must be a string");
if (typeof a !== "string") throw Error("View vendor must be a string");
if (typeof g !== "number") throw Error("Duration must be a number");
typeof data !== "string" && (data = "");
d.rpc("log_view", [b, c, a, g], h, f, this, !0, 2, "log_view")
};
this.init =
function(b) {
d = b
}
};
Spotify.Logging.Logger = function() {
Spotify.EventTarget.call(this);
var d, h = function() {},
f = function() {};
this.serviceIsReady = !0;
this.logJSExceptions = function(b, c, a, g) {
typeof b === "undefined" || typeof c === "undefined" || typeof a === "undefined" || typeof g === "undefined" || d.rpc("log", [S_EXCEPTIONS_MESSAGE_TYPE, 1, b, c, a, g], h, f, this, !0, 2, "js_exceptions")
};
this.logRequestTime = function(b, c, a, g, i) {
typeof b === "undefined" || typeof c === "undefined" || typeof a === "undefined" || typeof g === "undefined" || typeof i === "undefined" || d.rpc("log", [30, 1, b, c, a, g, i], h, f, this, !0, 2, "request_time")
};
this.log = function(b, c) {
var a = Array.prototype.slice.call(arguments);
typeof b === "undefined" || typeof c === "undefined" || d.rpc("log", a, h, f, this, !0, 2, "log")
};
this.init = function(b) {
d = b
}
};
Spotify.PlayerTracker = function(d) {
Spotify.EventTarget.call(this);
var h = Spotify.DebuggerJS,
f, b = new Spotify.Events,
c = null,
a = {},
g, i = 0,
n = 0,
l = 0,
m, o = 0,
k = [],
p = 0,
q = 0,
s = 0,
u = 0,
w = 0,
v = 0,
t = "",
y = "unknown",
C = "unknown",
x = "unknown",
z = "unknown",
B = "unknown",
M = "unknown",
H = "unknown",
E = "unknown",
F = "",
D = new Spotify.Logging.Types,
G = new Spotify.Cache.Default(100, new Spotify.Cache.LocalStorage("tracker")),
I = !1,
J = !1,
O = !1,
L = !1,
N = {},
K = 0,
P = function(b) {
var f = a[b],
o = 0,
m = {};
if (F !== "") {
l = O ? l : T(k);
t = t || "";
y = y || "unknown";
C = C || "unknown";
z = z || "unknown";
M = M || "unknown";
H = H || "unknown";
E = E || "unknown";
if (p === 0 && q === 0 && (b === D.TRACK_END || b === D.AD_END)) i = n = l;
if (b === D.AD_END) m.ad_file_id = d.ad.file_id, m.lid = d.ad.ad_id, m.file_id = "5", m.bytes_played = 0, m.content_length = 0, m.ms_rcv_latency = 0, m.num_stutter = 0, m.p_lowbuffer = 0, m.skipped = 0, m.last_stream_started_at = (new Date(w)).toISOString(), m.token = d.ad.token, m.clicked = d.ad.has_been_clicked ? 1 : 0, m["client-ad-count"] = d.ad.adPlayCount, m["client-campaign-count"] = d.ad.campaignPlayCount, m.source_start = "pendad", m.source_end = "trackdone", m.reason_end = "albumtrackdone";
else if (b === D.TRACK_END) m.lid = F, m.source_start = C, m.source_end = x, m.reason_end = B;
else if (b === D.TRACK_PROGRESS) m.lid = F, m.play_track = g, m.source_start = C, m.bitrate = d.bitrate, m.audiocodec = d.audiocodec;
m.max_continuous = i;
m.ms_played = n;
m.ms_played_union = l;
m.n_seeks_forward = p;
m.n_seeks_backward = q;
m.ms_seeks_forward = s;
m.ms_seeks_backward = u;
m.ms_latency = v;
m.display_track = t;
m.play_context = y;
m.reason_start = z;
m.referrer = M;
m.referrer_version = H;
for (m.referrer_vendor =
E; o < f.length; o++) f[o].log(m);
if (b === D.AD_END) {
if (!O && c) c.onReady(function() {
c.recordAdEvent("spotify:ad:" + d.ad.file_id, "impression")
});
delete d.ad
}
O && (O = !1);
h.log("Spotify.PlayerTracker", ["Logging song data -> Type:", b, "-> Arguments:", m], "corejs")
}
},
Q = function(b) {
var c = a[D.TRACK_EVENT],
g = 0;
if (F !== "") for (b = {
lid: F,
event: b,
ms_where: d.position()
}; g < c.length; g++) c[g].log(b)
},
A = function() {
o = d.position();
n += 500;
if ((n % 15E3 === 0 || n < 1E3) && K < 4 && !L) P(D.TRACK_PROGRESS), K++
},
R = function() {
m !== null && clearTimeout(m)
},
W = function() {
h.log("Spotify.PlayerTracker", ["Cache is initialized..."], "corejs");
I = !0
},
X = function() {
I = !1
},
Y = function(a) {
h.log("Spotify.PlayerTracker", ["endSongData are now stored", arguments], "corejs")
},
Z = function(a) {
h.error("Spotify.PlayerTracker", ["endSongData are NOT stored", arguments], "corejs")
},
U = function(a, b) {
if (b !== null) {
G.remove("stats", V, f);
var c;
c = JSON.parse(Spotify.Utils.Base64.decode(b));
if (c.isAd) {
J = !0;
if (!d.ad) d.ad = {};
d.ad.file_id = c.ad_file_id;
d.ad.ad_id = c.ad_id;
w = c.last_stream_started_at;
d.ad.token = c.token;
d.ad.has_been_clicked = c.clicked;
d.ad.adPlayCount = c["client-ad-count"];
d.ad.campaignPlayCount = c["client-campaign-count"]
} else J = !1;
F = c.lid;
i = c.max_continuous;
l = c.ms_played_union;
n = c.ms_played;
p = c.n_seeks_forward;
q = c.n_seeks_backward;
s = c.ms_seeks_forward;
u = c.ms_seeks_backward;
v = c.ms_latency;
t = c.display_track;
y = c.play_context;
C = c.source_start;
x = c.source_end;
z = c.reason_start;
B = c.reason_end;
M = c.referrer;
H = c.referrer_version;
E = c.referrer_vendor;
O = !0;
J ? (J = !1, P(D.AD_END)) : P(D.TRACK_END);
S()
}
},
V = function() {},
S = function() {
F = "";
n = 0;
g = "";
l = i = 0;
k = [];
v = u = s = q = p = 0;
t = "";
E = H = M = B = z = x = C = y = "unknown"
},
aa = function(a, b) {
return a.time - b.time
},
T = function(a) {
for (var b = 0, c = 0, g = 0, d = 0, l = 0, f = 0; l < a.length; l++) l % 2 !== 0 && typeof a[l - 1] !== "undefined" && a[l - 1].type === "START" && (f = a[l].time - a[l - 1].time, i = f > i ? f : i);
for (a.sort(aa); d < a.length; d++) a[d].type === "START" && (c === 0 && (g = d), ++c), a[d].type === "END" && (--c, c === 0 && (b += a[d].time - a[g].time));
return b
},
ca = function() {
var a = {};
L ? (a.isAd = !0, a.ad_file_id = d.ad.file_id, a.lid =
d.ad.ad_id, a.last_stream_started_at = w, a.token = d.ad.token, a.clicked = d.ad.has_been_clicked, a["client-ad-count"] = d.ad.adPlayCount, a["client-campaign-count"] = d.ad.campaignPlayCount, a.source_start = "pendad") : (a.isAd = !1, a.source_start = C || "unknown", a.lid = F);
a.source_end = a.source_start;
a.max_continuous = i;
a.ms_played = n;
a.ms_played_union = T(k);
a.n_seeks_forward = p;
a.n_seeks_backward = q;
a.ms_seeks_forward = s;
a.ms_seeks_backward = u;
a.ms_latency = v;
a.display_track = t || "";
a.play_context = y || "unknown";
a.reason_start = z || "unknown";
a.reason_end = "reload";
a.referrer = M || "unknown";
a.referrer_version = H || "unknown";
a.referrer_vendor = E || "unknown";
G.put("stats", Spotify.Utils.Base64.encode(JSON.stringify(a)), Y, Z, null, this)
},
ba = function() {
k.push({
type: "END",
time: o
});
L ? P(D.AD_END) : P(D.TRACK_END);
R();
S()
};
this.onPositionChanged = function() {
if (F !== "") {
var a = d.position();
k.push({
type: "END",
time: o
});
a >= o ? (p++, s += a - o) : (q++, u += o - a);
o = a;
k.push({
type: "START",
time: o
});
h.log("Spotify.PlayerTracker", ["Tracking the position changed event"], "corejs")
}
};
this.onConnected = function() {
h.log("Spotify.PlayerTracker", ["Tracking the on connect event"], "corejs");
F !== "" && (d.isPlaying ? (h.log("Spotify.PlayerTracker", ["Tracking the reconnect while playing event"], "corejs"), Q(1)) : d.isPaused && (h.log("Spotify.PlayerTracker", ["Tracking the reconnect while being paused event"], "corejs"), Q(2)))
};
this.onTrackEnded = function() {
K = 0;
ba();
h.log("Spotify.PlayerTracker", ["Tracking the track end event"], "corejs")
};
this.onPlayRequest = function(a) {
w = a.params.timestamp
};
this.onSongLoaded = function() {};
this.onLoaded = function() {
F = d.lid;
g = d.trackUri;
L = d.isAd;
v = (new Date).getTime() - w;
t = N.display_track || "";
y = N.play_context || "unknown";
C = N.source_start || "unknown";
z = N.reason_start || "unknown";
M = N.referrer || "unknown";
H = N.referrer_version || "unknown";
E = N.referrer_vendor || "unknown"
};
this.onPlaying = function() {
var a = d.position();
k.push({
type: "START",
time: a
});
R();
m = setInterval(A, 500);
Q(3);
h.log("Spotify.PlayerTracker", ["Tracking the on play event"], "corejs")
};
this.onPause = function() {
R();
Q(4);
h.log("Spotify.PlayerTracker", ["Tracking the on pause event"], "corejs")
};
this.onStopped = function() {
h.log("Spotify.PlayerTracker", ["Tracking the on stopped event"], "corejs");
K = 0;
ba()
};
this.onInvalidTrackUri = function() {
h.log("Spotify.PlayerTracker", ["Tracking the invalid track uri event"], "corejs")
};
this.onPlaybackFailed = function() {
R();
S();
h.log("Spotify.PlayerTracker", ["Tracking the playback failed event"], "corejs")
};
this.setEndSongStartLog = function(a) {
typeof a !== "undefined" && (N = a)
};
this.setEndSongStopLog =
function(a) {
typeof a !== "undefined" && (x = a.source_end || "unknown", B = a.reason_end || "unknown")
};
this.getStoredEndSongDataFromCache = function() {
I && G.get("stats", U, this)
};
this.dispose = function() {
ca()
};
this.addLogger = function(b, c) {
typeof a[b] === "undefined" && (a[b] = []);
a[b].push(c)
};
this.setAdService = function(a) {
c = a
};
this.initialize = function() {
f = this;
G.initialize(W, X, this);
d.bind(b.TRACK_ENDED, f.onTrackEnded, f);
d.bind(b.POSITION_CHANGED, f.onPositionChanged, f);
d.bind(b.PLAYING, f.onPlaying, f);
d.bind(b.PAUSED, f.onPause, f);
d.bind(b.STOPPED, f.onStopped, f);
d.bind(b.INVALID_TRACK_URI, f.onInvalidTrackUri, f);
d.bind(b.PLAYBACK_FAILED, f.onPlaybackFailed, f);
d.bind(b.TRACK_PLAY_REQUEST, f.onPlayRequest, f);
d.bind(b.SONG_LOADED, f.onSongLoaded, f);
d.bind(b.ON_LOAD, f.onLoaded, f)
}
};
Spotify.Protobuf.Parser = function() {
function d() {}
function h(a) {
var b = g[a.current.value],
c = a.next().value,
d = a.next().value;
a.expectToken("=");
var f = ~~a.next().value;
a.skipUntil(";");
return {
name: d,
number: f,
label: b,
type: i[c],
type_name: i[c] ? void 0 : c,
default_value: void 0
}
}
function f(a, c) {
c = {
name: a.next().value,
field: [],
nested_type: [],
enum_type: []
};
for (a.expectToken("{"); a.next().type != "}";) switch (a.current.value) {
case "optional":
case "repeated":
case "required":
c.field.push(h(a));
break;
case "message":
c.nested_type.push(f(a));
break;
case "enum":
c.enum_type.push(b(a));
break;
case "extensions":
a.skipUntil(";");
break;
case ";":
break;
default:
a.fail("Unrecognized message token: " + a.current.value)
}
return c
}
function b(a) {
var b = a.next().value;
a.expectToken("{");
for (var c = []; a.next().type != "}";) {
var g = a.current.value;
a.expectToken("=");
var i = ~~a.next().value;
c.push({
name: g,
number: i
});
a.skipUntil(";")
}
return {
name: b,
value: c
}
}
var c = {};
d.Label = {
LABEL_OPTIONAL: 1,
LABEL_REQUIRED: 2,
LABEL_REPEATED: 3
};
d.Type = {
TYPE_DOUBLE: 1,
TYPE_FLOAT: 2,
TYPE_INT64: 3,
TYPE_UINT64: 4,
TYPE_INT32: 5,
TYPE_FIXED64: 6,
TYPE_FIXED32: 7,
TYPE_BOOL: 8,
TYPE_STRING: 9,
TYPE_MESSAGE: 11,
TYPE_BYTES: 12,
TYPE_UINT32: 13,
TYPE_ENUM: 14,
TYPE_SFIXED32: 15,
TYPE_SFIXED64: 16,
TYPE_SINT32: 17,
TYPE_SINT64: 18
};
var a = function(a) {
this.text = a;
this.ptr = 0;
this.current = {
value: "",
type: "",
ptr: 0
}
};
a.prototype = {
where: function(a) {
for (var a = a === void 0 ? this.current.ptr : a, b = 0, c = -1; c && c <= a;) c = this.text.indexOf("\n", c) + 1, ++b;
return "line: " + b
},
fail: function(a, b) {
throw this.where(b) + ": " + a;
},
skipWhitespace: function() {
for (var a =
this.text[this.ptr]; a && " \t\r\n".indexOf(a) != -1;) a = this.text[++this.ptr]
},
skipLineComment: function() {
for (var a = this.text[this.ptr]; a && a !== "\r" && a !== "\n";) a = this.text[++this.ptr];
a === "\r" && (a = this.text[++this.ptr]);
a === "\n" && ++this.ptr
},
skipBlockComment: function() {
for (var a = this.ptr, b = this.text[this.ptr], c = !1; b && !(c && b === "/");) c = b === "*", b = this.text[++this.ptr];
b || this.fail("Expected end of block comment", a);
++this.ptr
},
skipUntil: function(a) {
for (var b = this.ptr; this.next().type !== a;) this.current.type === "" && this.fail("Expected: " + a + "(Unexpected end of data)", b)
},
expectToken: function(a) {
this.next().type !== a && this.fail("Expected: " + a)
},
extractWord: function() {
for (var a = this.ptr, b = this.text[this.ptr]; b && "{}[]=; \t\r\n/".indexOf(b) === -1;) b = this.text[++this.ptr];
this.current.type = "word";
this.current.value = this.text.substring(a, this.ptr)
},
extractString: function() {
var a = this.text.indexOf('"', this.ptr + 1);
this.current.type = "string";
this.current.value = this.text.substring(this.ptr + 1, a - 1);
this.ptr = a + 1
},
next: function() {
this.skipWhitespace();
for (var a = this.text[this.ptr]; a === "/";) a = this.text[++this.ptr], a === "/" ? (++this.ptr, this.skipLineComment()) : a === "*" ? (++this.ptr, this.skipBlockComment()) : this.fail("Expecting // or /*", this.ptr - 1), this.skipWhitespace(), a = this.text[this.ptr];
this.current.ptr = this.ptr;
this.ptr >= this.text.length ? (this.current.value = "", this.current.type = "") : "{}[]=;".indexOf(a) !== -1 ? (this.current.value = this.current.type = a, ++this.ptr) : a === '"' ? this.extractString() : this.extractWord();
return this.current
}
};
var g = {
optional: "LABEL_OPTIONAL",
required: "LABEL_REQUIRED",
repeated: "LABEL_REPEATED"
},
i = {
"double": "TYPE_DOUBLE",
"float": "TYPE_FLOAT",
int64: "TYPE_INT64",
uint64: "TYPE_UINT64",
int32: "TYPE_INT32",
fixed64: "TYPE_FIXED64",
fixed32: "TYPE_FIXED32",
bool: "TYPE_BOOL",
string: "TYPE_STRING",
bytes: "TYPE_BYTES",
uint32: "TYPE_UINT32",
sfixed32: "TYPE_SFIXED32",
sfixed64: "TYPE_SFIXED64",
sint32: "TYPE_SINT32",
sint64: "TYPE_SINT64"
};
c.parseFileDescriptor = function(c) {
for (var c = new a(c), g = {
message_type: [],
enum_type: []
}; c.next().type != "";) switch (c.current.value) {
case "package":
case "option":
c.skipUntil(";");
break;
case "message":
g.message_type.push(f(c));
break;
case "enum":
g.enum_type.push(b(c));
break;
default:
c.fail("Unrecognized proto token: " + c.current.value)
}
return g
};
c.FieldDescriptorProto = d;
return c
}();
Spotify.Protobuf.Serialization = function() {
function d() {
this._data = []
}
function h(a, b, c) {
this._data = a;
this._ptr = b;
this._end = this._ptr + c
}
function f(a, b, c, g) {
switch (b.type) {
case "int32":
g.writeVarint(b.id << 3 | 0);
g.writeVarint(c);
break;
case "uint32":
g.writeVarint(b.id << 3 | 0);
g.writeVarint(~~c);
break;
case "sint32":
g.writeVarint(b.id << 3 | 0);
g.writeVarint(c << 1 ^ c >> 31);
break;
case "int64":
case "uint64":
g.writeVarint(b.id << 3 | 0);
g.writeVarint64(Math.floor(c / 4294967296), ~~c);
break;
case "sint64":
g.writeVarint(b.id << 3 | 0);
b = Math.abs(c) - (c < 0);
g.writeVarint64(Math.floor(b / 2147483648), (b << 1) + (c < 0));
break;
case "bool":
g.writeVarint(b.id << 3 | 0);
g.writeVarint(c ? 1 : 0);
break;
case "string":
g.writeVarint(b.id << 3 | 2);
b = [];
for (a = 0; a < c.length; ++a) {
var i = c.charCodeAt(a);
if (i < 128) b.push(i);
else {
if ((i & 64512) === 55296) var l = c.charCodeAt(++a),
i = ((i & 1023) << 10 | l & 1023) + 65536;
i < 2048 ? b.push(192 | i >> 6) : (i < 65536 ? b.push(224 | i >> 12) : (b.push(240 | i >> 18), b.push(128 | i >> 12 & 63)), b.push(128 | i >> 6 & 63));
b.push(128 | i & 63)
}
}
c = b;
g.writeVarint(c.length);
g.writeAll(c);
break;
case "bytes":
g.writeVarint(b.id << 3 | 2);
b = [];
for (a = 0; a < c.length; ++a) b.push(c.charCodeAt(a));
c = b;
g.writeVarint(c.length);
g.writeAll(c);
break;
case "*":
for (i = 0; i < c.length; ++i) f(a, b.subField, c[i], g);
break;
case "#":
b.enumMap.toNumber.hasOwnProperty(c);
c = b.enumMap.toNumber[c];
g.writeVarint(b.id << 3 | 0);
g.writeVarint(c);
break;
default:
if (a.hasOwnProperty(b.type)) i = new d, a[b.type].serializeToStream(c, i), g.writeVarint(b.id << 3 | 2), g.writeVarint(i._data.length), g.writeAll(i._data);
else
throw "Unsupported type";
}
}
function b(a) {
for (var b = [], c = 0; c < a.length;) {
var g = a.charCodeAt(c++);
if (g < 128) b.push(a[c - 1]);
else {
var i;
g < 224 ? (g &= -225, i = 2) : g < 240 ? (g &= -241, i = 3) : (g &= -249, i = 4);
for (; --i && c < a.length;) var d = a.charCodeAt(c++),
g = g << 6 | d & -193;
g < 65536 ? b.push(String.fromCharCode(g)) : (g -= 65536, b.push(String.fromCharCode(55296 | g >> 10, 56320 | g & 1023)))
}
}
return b.join("")
}
function c(a) {
return decodeURIComponent(escape(a))
}
function a(b, c) {
var g = c.name;
switch (c.type) {
case "int32":
return function(a, b, c, i) {
return a === 0 ? (c[g || i] = ~~b.readVarint(), !0) : !1
};
case "uint32":
return function(a, b, c, i) {
return a === 0 ? (c[g || i] = b.readVarint(), !0) : !1
};
case "sint32":
return function(a, b, c, i) {
return a === 0 ? (a = g || i, b = b.readVarint(), c[a] = b >>> 1 ^ -(b & 1), !0) : !1
};
case "int64":
return function(a, b, c, i) {
return a === 0 ? (a = b.readVarint64(), c[g || i] = a.hi * 4294967296 + ((a.lo >>> 1) * 2 + (a.lo & 1)), !0) : !1
};
case "uint64":
return function(a, b, c, i) {
return a === 0 ? (a = b.readVarint64(), c[g || i] = ((a.hi >>> 1) * 2 + (a.hi & 1)) * 4294967296 + ((a.lo >>> 1) * 2 + (a.lo & 1)), !0) : !1
};
case "sint64":
return function(a, b, c, i) {
return a === 0 ? (a = b.readVarint64(), b = ((a.hi >>> 1) * 2 + (a.hi & 1)) * 2147483648 + (a.lo >>> 1), c[g || i] = a.lo & 1 ? -1 - b : b, !0) : !1
};
case "bool":
return function(a, b, c, i) {
return a === 0 ? (c[g || i] = b.readVarint() !== 0, !0) : !1
};
case "string":
return function(a, b, c, i) {
return a === 2 ? (a = b.readVarint(), c[g || i] = q(b.bytes(a)), !0) : !1
};
case "bytes":
return function(a, b, c, i) {
return a === 2 ? (a = b.readVarint(), c[g || i] = b.bytes(a), !0) : !1
};
case "*":
var i = a(b, c.subField);
return g ?
function(a, b, c) {
c = c[g] ? c[g] : c[g] = [];
return i(a, b, c, c.length)
} : function(a, b, c, g) {
c = c[g] ? c[g] : c[g] = [];
return i(a, b, c, c.length)
};
case "#":
var d = c.enumMap.toName;
return function(a, b, c, i) {
return a === 0 ? (a = b.readVarint(), c[g || i] = d.hasOwnProperty(a) ? d[a] : a, !0) : !1
}
}
return function(a, i, d, f) {
return a === 2 ? (a = i.readVarint(), i = i.substream(a), b[c.type].parseFromStream(i, d[g || f] = {}), !0) : !1
}
}
function g(b) {
for (var c = this, g = 0; g < b.length; ++g)(function(b) {
for (var g = [], i = {}, l = b.fields, n = 0; n < l.length; ++n) {
var o = l[n];
if (o.type[0] === "*") var m = {
type: o.type.substr(1),
id: o.id,
enumMap: o.enumMap
},
o = {
type: "*",
id: o.id,
name: o.name,
subField: m
};
g[o.id] = a(c, o);
i[o.name] = o
}
c[b.name] = {
serializeToStream: function(a, b) {
for (var g in a) i.hasOwnProperty(g) && f(c, i[g], a[g], b)
},
parseFromStream: function(a, c) {
for (; !a.empty();) {
var i = a.readVarint(),
d = i >>> 3;
i &= 7;
var f = g[d];
try {
if (!f || !f(i, a, c)) switch (f = a, i) {
case 0:
f.skipVarint();
break;
case 1:
f.skip(8);
break;
case 2:
var l = f.readVarint();
f.skip(l);
break;
case 3:
case 4:
throw "Deprecated wire type";
case 5:
f.skip(4);
break;
default:
throw "Unsupported wire type";
}
} catch (h) {
throw k.error("Spotify.Protobuf.Serialization", ["Error in", b, d, i], "corejs"), h;
}
}
},
serializeToString: function(a, b) {
b(serializeToStringSync(a))
},
serializeToStringSync: function(a) {
var g = new d;
c[b.name].serializeToStream(a, g);
return g.toString()
},
parseFromString: function(a, b) {
b(parseFromStringSync(a))
},
parseFromStringSync: function(a) {
var a = new h(a, 0, a.length),
g = {};
c[b.name].parseFromStream(a, g);
return g
}
}
})(b[g])
}
function i(a, b, c, g) {
var i = null;
a.type_name ? (i = a.type_name, i = c.hasOwnProperty(g + i) ? c[g + i] : c.hasOwnProperty(i) ? c[i] : null, b = i ? b ? "int32" : "#" : a.type_name) : b = s[a.type];
return {
id: a.number,
type: (a.label === "LABEL_REPEATED" ? "*" : "") + b,
name: a.name,
typeName: a.type_name,
enumMap: i
}
}
function n(a, b, c, g) {
for (var d = {
name: a.name,
fields: []
}, f = 0; f < a.field.length; ++f) d.fields.push(i(a.field[f], b, c, g + a.name + "."));
return d
}
function l(a, b, c) {
for (var g = 0; g < a.length; ++g) {
for (var i = c + a[g].name, d = b, f = i, l = a[g].value, k = {}, h = {}, n = 0; n < l.length; ++n) {
var o = l[n];
k[o.number] = o.name;
h[o.name] = o.number
}
d[f] = {
name: i,
toName: k,
toNumber: h
}
}
}
function m(a, b, c) {
for (var g = 0; g < a.length; ++g) {
var i =
c + a[g].name + ".";
m(a[g].nested_type, b, i);
l(a[g].enum_type, b, i)
}
}
var o = {},
k = Spotify.DebuggerJS;
d.prototype.write = function(a) {
this._data.push(a)
};
d.prototype.writeAll = function(a) {
Array.prototype.push.apply(this._data, a)
};
d.prototype.writeVarint = function(a) {
for (; a & -128;) this.write(a & 127 | 128), a >>>= 7;
this.write(a)
};
d.prototype.writeVarint64 = function(a, b) {
a ? (this.write(b & 127 | 128), this.write(b >>> 7 & 127 | 128), this.write(b >>> 14 & 127 | 128), this.write(b >>> 21 & 127 | 128), a & -8 ? (this.write((a << 4 | b >>> 28) & 127 | 128), this.writeVarint(a >>> 3)) : this.write((a << 4 | b >>> 28) & 127)) : this.writeVarint(b)
};
d.prototype.toString = function() {
var a;
a = this._data;
if (a.length < p) a = String.fromCharCode.apply(String, a);
else {
var b = 0,
c = [];
do c.push(String.fromCharCode.apply(String, a.slice(b, b + p))), b += p;
while (b < a.length);
a = c.join("")
}
return a
};
h.prototype.empty = function() {
return this._ptr >= this._end
};
h.prototype.skipVarint = function() {
for (; this._data.charCodeAt(this._ptr++) >= 128;);
};
h.prototype.readVarint = function() {
var a = 0,
b = 1;
do {
var c = this._data.charCodeAt(this._ptr++);
a += (c & 127) * b;
b *= 128
} while (c >= 128);
return a
};
h.prototype.readVarint64 = function() {
var a = 0,
b = 1 / 4294967296,
c = 0,
g = 1;
do {
var i = this._data.charCodeAt(this._ptr++);
a |= (i & 127) * b;
c |= (i & 127) * g;
b *= 128;
g *= 128
} while (i >= 128);
return {
hi: a,
lo: c
}
};
h.prototype.skip = function(a) {
this._ptr += a
};
h.prototype.substream = function(a) {
var b = this._ptr;
this._ptr += a;
return new h(this._data, b, a)
};
h.prototype.bytes = function(a) {
var b = this._ptr;
this._ptr += a;
return this._data.substr(b, a)
};
var p = 4096,
q = decodeURIComponent && escape ? c : b,
s = {
TYPE_INT32: "int32",
TYPE_SINT32: "sint32",
TYPE_UINT32: "uint32",
TYPE_STRING: "string",
TYPE_BYTES: "bytes",
TYPE_BOOL: "bool",
TYPE_DOUBLE: "double",
TYPE_INT64: "int64",
TYPE_UINT64: "uint64",
TYPE_SINT64: "sint64"
};
o.createFromJson = function(a) {
return new g(a)
};
o.createFromFileDescriptor = function(a, b) {
var c = b === void 0 ? !1 : b,
i = [],
d = {};
l(a.enum_type, d, "");
m(a.message_type, d, "");
for (var f = 0; f < a.message_type.length; ++f) i.push(n(a.message_type[f], c, d, ""));
return new g(i)
};
return o
}();
(function() {
var d = [].slice;
if (!("bind" in Function.prototype)) Function.prototype.bind = function(f) {
var b = this,
c = null;
arguments.length > 1 && (c = d.call(arguments, 1));
return function() {
var a;
!arguments.length && !c ? a = b.call(f) : b.apply(f, !c ? arguments : !arguments.length ? c : c.concat(d.call(arguments)));
return a
}
};
if (!("indexOf" in Array.prototype)) Array.prototype.indexOf = function() {
for (var d = this.length >>> 0, b = from < 0 ? Math.max(0, d + from) : from || 0; b < d; b++) if (this[b] === item) return b;
return -1
};
var h;
Spotify.Utils = {
isArray: Array.isArray ||
function(d) {
return Object.prototype.toString.call(d) == "[object Array]"
},
isFunction: function(d) {
return typeof d == "function"
},
toFixed: function(d, b) {
var b = b || 0,
c = d < 0,
a = Math.pow(10, b),
d = Math.round(d * a),
g = String((c ? Math.ceil : Math.floor)(d / a)),
c = String((c ? -d : d) % a),
a = Array(Math.max(b - c.length, 0) + 1).join("0");
return b ? g + "." + a + c : g
},
convertStringToXML: function(d) {
if (window.DOMParser) return h = new DOMParser, h.parseFromString(d.replace(/\n/g, ""), "text/xml");
else {
var b = new ActiveXObject("Microsoft.XMLDOM");
b.async = !1;
return b.loadXML(d.replace(/\n/g, ""))
}
},
convertXMLToJSON: function(d) {
var b = {},
c = 0,
a = /\S/;
if (d.nodeType === 1) {
if (d.attributes.length > 0) {
b["@attributes"] = {};
for (var g = 0; g < d.attributes.length; g++) {
var i = d.attributes.item(g);
b["@attributes"][i.nodeName] = i.nodeValue
}
}
} else if (d.nodeType === 3 && a.test(d.data)) b = d.data;
if (d.hasChildNodes()) for (; c < d.childNodes.length; c++) g = d.childNodes[c], i = g.nodeName, g.nodeType === 3 ? a.test(g.data) && (b = this.convertXMLToJSON(g)) : typeof b[i] === "undefined" ? b[i] = this.convertXMLToJSON(g) : (this.isArray(b[i]) || (b[i] = Array(b[i])), b[i].push(this.convertXMLToJSON(g)));
return b
},
hex2str: function(d) {
for (var b = [], c = 0, a = d.length; c < a - 1; c += 2) b.push(String.fromCharCode(parseInt(d.substr(c, 2), 16)));
return b.join("")
},
str2hex: function(d) {
for (var b = "", c = 0, a = d.length; c < a; ++c) b += (d.charCodeAt(c) + 256).toString(16).slice(-2);
return b
}
}
})();
Spotify.Utils.Base62 = function() {
function d(a, b, c) {
for (var d = [0], f = [1], h = 0; h < a.length; ++h) {
for (var k = d, p = f, q = a[h], s = c, u = 0, w = 0; w < p.length; ++w) u = ~~k[w] + p[w] * q + u, k[w] = u % s, u = ~~ (u / s);
for (; u;) u = ~~k[w] + u, k[w] = u % s, u = ~~ (u / s), ++w;
k = f;
p = b;
q = c;
for (s = w = 0; s < k.length; ++s) w = k[s] * p + w, k[s] = w % q, w = ~~ (w / q);
for (; w;) k.push(w % q), w = ~~ (w / q)
}
return d
}
function h(a, b) {
for (var c = 0, d = []; c < a.length; ++c) d.push(b[a[c]]);
return d.reverse()
}
function f(a, b) {
for (; a.length < b;) a.push(0);
return a
}
for (var b = {}, c = {}, a = 0; a < 62; ++a) c["0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" [a]] =
a;
for (a = 0; a < 16; ++a) b["0123456789abcdef" [a]] = a;
for (a = 0; a < 16; ++a) b["0123456789ABCDEF" [a]] = a;
return {
fromBytes: function(a, b) {
var c = d(a.slice(0).reverse(), 256, 62);
return h(f(c, b), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").join("")
},
toBytes: function(a, b) {
var n = d(h(a, c), 62, 256);
return f(n, b).reverse()
},
toHex: function(a, b) {
var n = d(h(a, c), 62, 16);
return h(f(n, b), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").join("")
},
fromHex: function(a, c) {
var n = d(h(a, b), 16, 62);
return h(f(n, c), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").join("")
}
}
}();
Spotify.Utils.Base64 = function() {
for (var d = [], h = 0; h < 256; ++h) d[h] = 255;
for (h = 0; h < 64; ++h) d["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(h)] = h;
var f = String.fromCharCode.apply(String, d);
return {
encode: function(b) {
var c, a, g, i, d, l;
g = b.length;
a = 0;
for (c = ""; a < g;) {
i = b.charCodeAt(a++) & 255;
if (a == g) {
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(i >> 2);
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt((i & 3) << 4);
c += "==";
break
}
d =
b.charCodeAt(a++);
if (a == g) {
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(i >> 2);
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt((i & 3) << 4 | (d & 240) >> 4);
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt((d & 15) << 2);
c += "=";
break
}
l = b.charCodeAt(a++);
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(i >> 2);
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt((i & 3) << 4 | (d & 240) >> 4);
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt((d & 15) << 2 | (l & 192) >> 6);
c += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(l & 63)
}
return c
},
decode: function(b) {
for (var c = [], a = b.length, g, i, d = 0;;) {
do g = f.charCodeAt(b.charCodeAt(d++) & 255);
while (g === 255 && d < a);
do i = f.charCodeAt(b.charCodeAt(d++) & 255);
while (i === 255 && d < a);
if (i === 255) break;
c.push((g << 2 | i >> 4) & 255);
do g = f.charCodeAt(b.charCodeAt(d++) & 255);
while (g === 255 && d < a);
if (g === 255) break;
c.push((i << 4 | g >> 2) & 255);
do i = f.charCodeAt(b.charCodeAt(d++) & 255);
while (i === 255 && d < a);
if (i === 255) break;
c.push((g << 6 | i) & 255)
}
if (c.length < 4096) c = String.fromCharCode.apply(String, c);
else {
b = 0;
a = [];
do a.push(String.fromCharCode.apply(String, c.slice(b, b + 4096))), b += 4096;
while (b < c.length);
c = a.join("")
}
return c
}
}
}();
Spotify.Heartbeat = function(d) {
var h = new Spotify.Events,
f = null,
b;
this.initialize = function() {
b = this;
d.bind(h.ON_TRY_TO_CONNECT, i, b);
d.bind(h.DISCONNECTED, i, b);
d.bind(h.CONNECTED, n, b)
};
this.start = function() {
this.stop();
f = setInterval(g, 18E4)
};
this.stop = function() {
f !== null && (clearInterval(f), f = null)
};
var c = function() {},
a = function() {},
g = function() {
d.rpc("echo", "h", c, a, b, !1, 0, "heartbeat")
},
i = function() {
this.stop()
},
n = function() {
this.start()
}
};
Spotify.Gateway = function(d, h) {
Spotify.EventTarget.call(this);
var f = Spotify.DebuggerJS,
b = new Spotify.Logging.Logger,
c = !1,
a = new Spotify.Events,
g = new Spotify.Logging.Types,
i = [],
n = 0,
l = this;
this.player = this.bridge = null;
var m, o, k = !1,
p = !1,
q, s;
this.isConnected = !1;
this.rpc = function(b, c, g, i, d, l, k, h) {
g = m.addCall(b, c, g, i, d, l, k, h);
f.log("Spotify.Gateway", ["Call with method", b, "calltype", h, "params", c, "and request id", g, "was executed"], "corejs");
this.isConnected ? p ? q.addToBucket(g) : this.bridge.rpc(b, c, g) : (l ? m.setPersistent(g, !0) : m.setPersistent(g, !1), o.reset(), this.trigger(a.DISCONNECTED))
};
this.disconnect = function() {
this.bridge.disconnect()
};
this.connect = function(a) {
this.bridge.connect(a, B())
};
var u = function() {
this.isConnected = !0
},
w = function(a) {
f.log("Spotify.Gateway", ["onTimeout", a], "corejs")
},
v = function(b) {
l.trigger(a.HERMES_B64_MESSAGE, b.params)
},
t = function() {
l.trigger(a.USER_INFO_CHANGE)
},
y = function() {
k = !0;
this.playerTracker.getStoredEndSongDataFromCache();
if (this.playerTracker && k) this.playerTracker.onConnected();
this.trigger(a.CONNECTED);
for (var b = 0, c = m.getPersistentCalls(), g = c.length, i; b < g; b++) i = c[b], l.rpc(i.method, i.params, i.callback, i.errback, i.context, i.persistent);
b = 0;
c = m.getCalls();
for (g = c.length; b < g; b++) i = c[b], i.method !== "work_done" && l.rpc(i.method, i.params, i.callback, i.errback, i.context, i.persistent, i.retries--)
},
C = function() {
this.isConnected = !1
},
x = function() {
l.trigger(a.ON_TRY_TO_CONNECT)
},
z = function() {
l.trigger(a.DISCONNECTED)
},
B = function() {
var a = i[n];
n < i.length - 1 ? n++ : n = 0;
return a
},
M = function(a) {
var c =
m.getCall(a.params.requestId),
g, i = 0;
try {
i = JSON.stringify(a.params.response).length
} catch (d) {}
typeof c !== "undefined" && (g = (new Date).getTime() - c.timestamp, f.log("Spotify.Gateway", ["Latency of call with request id", a.params.requestId, "is", g, "ms"], "corejs"), c.callback.call(c.context, a.params), c.callType !== "request_time" && c.callType !== "userdata" && c.callType !== "log_view" && c.callType !== "track_end" && c.callType !== "track_progress" && c.callType !== "log_ad" && c.callType !== "log_ce" && b.logRequestTime(c.callType, g, g, i, !1))
},
H = function(a) {
var c = [],
g = !0,
i = 0;
try {
i = JSON.stringify(a.params.response).length
} catch (d) {}
f.error("Spotify.Gateway", ["Got an RPC Error", a], "corejs");
if (typeof a.params.response !== "undefined") c = a.params.response;
if (c.length >= 3 && (c[0] === Spotify.Errors.Domains.HERMES_ERROR || c[0] === Spotify.Errors.Domains.HERMES_SERVICE_ERROR) && (c[1] === Spotify.Errors.Codes.HM_TOO_MANY_REQUESTS || c[1] === Spotify.Errors.Codes.HM_FAILED_TO_SEND_TO_BACKEND)) g = !1;
var g = m.getCall(a.params.requestId, g),
k;
typeof g !== "undefined" && (k = (new Date).getTime() - g.timestamp, f.log("Spotify.Gateway", ["Latency of call with request id", a.params.requestId, "is", k, "ms"], "corejs"), c.length >= 3 ? (c[0] === Spotify.Errors.Domains.HERMES_ERROR || c[0] === Spotify.Errors.Domains.HERMES_SERVICE_ERROR) && c[1] === Spotify.Errors.Codes.HM_TOO_MANY_REQUESTS ? (p = !0, q.start(), q.addToBucket(a.params.requestId)) : (c[0] === Spotify.Errors.Domains.HERMES_ERROR || c[0] === Spotify.Errors.Domains.HERMES_SERVICE_ERROR) && (c[1] === Spotify.Errors.Codes.HM_TIMEOUT || c[1] === Spotify.Errors.Codes.HM_FAILED_TO_SEND_TO_BACKEND) && g.retries > 0 ? l.rpc(g.method, g.params, g.callback, g.errback, g.context, g.persistent, g.retries - 1, g.callType) : (c.push(a.params.method), g.errback.call(g.context, new Spotify.Errors.Error(c))) : (f.log("Spotify.Gateway", ["RPC Error callback for method with id:", g.callType, g.params], "corejs"), g.errback.call(g.context, new Spotify.Errors.Error([1, 0, "", a.params]))), g.callType !== "request_time" && g.callType !== "userdata" && g.callType !== "log_view" && g.callType !== "track_end" && g.callType !== "track_progress" && g.callType !== "log_ad" && g.callType !== "log_ce" && b.logRequestTime(g.callType, k, k, i, !0))
},
E = function() {
l.player.isReady && c && l.trigger(a.READY)
},
F = function() {
c = !0;
E()
},
D = function(a) {
this.trigger(a.type, a.params)
},
G = function(b) {
switch (b.type) {
case a.READY:
l.player.isReady = !0;
E();
break;
case a.ON_LOAD:
l.player.isPaused = !0;
l.player.isStopped = !1;
l.player.isPlaying = !1;
l.player.isLoaded = !0;
l.player.onLoad(b);
break;
case a.PLAYING:
l.player.isPaused = !1;
l.player.isStopped = !1;
l.player.isPlaying = !0;
l.player.onPlay(b);
break;
case a.PAUSED:
l.player.isPaused = !0;
l.player.isStopped = !1;
l.player.isPlaying = !1;
l.player.onPause(b);
break;
case a.STOPPED:
l.player.isPaused = !1;
l.player.isStopped = !0;
l.player.isPlaying = !1;
l.player.isLoaded = !1;
l.player.onStop(b);
break;
case a.POSITION_CHANGED:
l.player.onPositionChanged(b);
break;
case a.TRACK_ENDED:
l.player.isPaused = !1;
l.player.isStopped = !0;
l.player.isPlaying = !1;
l.player.onTrackEnded(b);
break;
case a.SONG_LOADED:
l.player.onSongLoaded(b);
break;
case a.CANNOT_PLAY_TRACK:
l.player.isLoaded = !1;
l.player.onInvalidTrackUri(b);
break;
case a.PLAYBACK_FAILED:
l.player.isStopped = !0;
l.player.isPaused = !1;
l.player.isPlaying = !1;
l.player.isLoaded = !1;
l.player.onPlaybackFailed(b);
break;
case a.INVALID_TRACK_URI:
l.player.onPlaybackFailed(b)
}
},
I = function() {
l.player.pause();
l.trigger(a.TOKEN_LOST)
},
J = function(a) {
var a = a.params,
b = m.getCall(a, !1);
f.log("Spotify.Gateway", ["onRateLimitCall Will try run the callback with id", a, b], "corejs");
b && l.bridge.rpc(b.method, b.params, a)
},
O = function() {
p = !1
};
this.dispose = function() {
this.player.isLoaded && this.playerTracker.dispose()
};
this.initialize = function(c, l) {
b.init(this);
var f;
m = new Spotify.CallsManager;
var k = new Spotify.Logging.TrackEnd;
k.init(this);
var n = new Spotify.Logging.TrackProgress;
n.init(this);
var p = new Spotify.Logging.TrackEvent;
p.init(this);
var B = new Spotify.Logging.AdEnd;
B.init(this);
i = l.connectionUri.split("|");
q = new Spotify.RateLimiter(1E3, 90);
q.bind(a.RATE_LIMIT_CALL, J, this);
q.bind(a.RATE_LIMIT_DISABLED, O, this);
if (d === Spotify.GatewayTypes.FLASH) this.bridge = new Spotify.Flash.Bridge(c);
else if (d === Spotify.GatewayTypes.WEBSOCKETS) this.bridge =
new Spotify.WebSockets.Bridge(c);
if (h === Spotify.PlayerTypes.FLASH_HTTP || h === Spotify.PlayerTypes.FLASH_RTMPS || h === Spotify.PlayerTypes.FLASH_AAC) f = L(c, l), d === Spotify.GatewayTypes.FLASH ? this.bridge.setFlashObject(f) : f.initialize(), this.player = new Spotify.Flash.Player({
flashObject: f
});
else if (h === Spotify.PlayerTypes.HTML5_HTTP) d === Spotify.GatewayTypes.FLASH && (f = L(c, l), this.bridge.setFlashObject(f)), this.player = new Spotify.HTML5.Player("html5audio");
if (typeof this.player !== "undefined" && this.player !== null) this.player.bind(a.TRACK_ENDED, G, this), this.player.bind(a.POSITION_CHANGED, G, this), this.player.bind(a.PLAYING, G, this), this.player.bind(a.PAUSED, G, this), this.player.bind(a.STOPPED, G, this), this.player.bind(a.CANNOT_PLAY_TRACK, G, this), this.player.bind(a.PLAYBACK_FAILED, G, this), this.player.bind(a.SONG_LOADED, G, this), this.player.bind(a.INVALID_TRACK_URI, G, this), this.player.bind(a.ON_LOAD, G, this), this.player.bind(a.READY, G, this), this.player.initialize(), this.playerTracker = new Spotify.PlayerTracker(this.player), this.playerTracker.addLogger(g.TRACK_END, k), this.playerTracker.addLogger(g.TRACK_EVENT, p), this.playerTracker.addLogger(g.AD_END, B), this.playerTracker.addLogger(g.TRACK_PROGRESS, n), this.playerTracker.initialize();
this.bridge.bind(a.CONNECTION_ESTABLISHED, u, this);
this.bridge.bind(a.FAILED_CONNECTING, C, this);
this.bridge.bind(a.RPC_CALLBACK, M, this);
this.bridge.bind(a.RPC_ERRBACK, H, this);
this.bridge.bind(a.TOKEN_LOST, I, this);
this.bridge.bind(a.HERMES_B64_MESSAGE, v, this);
this.bridge.bind(a.USER_INFO_CHANGE, t, this);
this.bridge.bind(a.LOGIN_COMPLETE, y, this);
this.bridge.bind(a.TIMEOUT, w, this);
this.bridge.bind(a.READY, F, this);
o = new Spotify.ConnectionManager;
o.bind(a.ON_TRY_TO_CONNECT, x, this);
o.bind(a.NOTIFY_OF_DISCONNECT, z, this);
o.initialize(this.bridge);
s = new Spotify.CodeValidator;
s.initialize(this, this.bridge);
this.bridge.initialize()
};
var L = function(b, c) {
var g = new Spotify.Flash.SWFObject({
playerType: c.playerType,
SWFFlashId: b,
SWFContainerId: c.SWFContainerId,
SWFUrl: c.SWFUrl,
SWFMinVersion: c.SWFMinVersion,
instanceId: b,
logging: c.logging,
length: c.valid,
authUrl: c.authUrl,
valid: 0
});
g.bind(a.FLASH_AVAILABLE, D, l);
g.bind(a.FLASH_UNAVAILABLE, D, l);
return g
}
};
Spotify.Flash.Bridge = function(d) {
Spotify.EventTarget.call(this);
var h = Spotify.DebuggerJS;
this.id = d;
var f;
this.rpc = function(b, c, a) {
typeof f !== void 0 ? f.isLoaded ? f.getSWF().sp_rpc.apply(f.getSWF(), [b, a].concat(c)) : h.error("Bridge", ["Core.Bridge:rpc: Bridge is not initialized"], "corejs") : h.error("Bridge", ["Core.Bridge:rpc: Bridge is not initialized"], "corejs")
};
this.disconnect = function() {
typeof f !== void 0 ? f.isLoaded ? f.getSWF().sp_disconnect.apply(f.getSWF()) : h.error("Bridge", ["Core.Bridge:Disconnect: Bridge is not initialized"], "corejs") : h.error("Bridge", ["Core.Bridge:Disconnect: Bridge is not initialized"], "corejs")
};
this.connect = function(b, c) {
b = b || "";
typeof f !== void 0 && f.isLoaded && f.getSWF().sp_connect.apply(f.getSWF(), [b, c])
};
this.initialize = function() {
f.initialize()
};
this.getFlashObject = function() {
return f
};
this.setFlashObject = function(b) {
f = b
}
};
Spotify.WebSockets.Bridge = function(d, h) {
Spotify.EventTarget.call(this);
var f = Spotify.DebuggerJS;
this.id = d;
var h = h || {},
b = this,
c = new Spotify.Events,
a = h.connectionParams || "",
g, i = null,
n = function() {
this.activate = function() {};
this.connect = function() {};
this.disconnect = function() {};
this.rpc = function() {};
this.onConnect = function() {};
this.onDisconnect = function() {};
this.onMessage = function() {};
this.onError = function() {}
},
l = null,
m = 0,
o = function(a) {
l = k[a];
l.activate()
},
k = {};
k[0] = new
function() {
n.call(this);
this.activate =
function() {
clearInterval(m)
};
this.connect = function() {
o(1)
}
};
k[1] = new
function() {
n.call(this);
this.activate = function() {
clearInterval(m);
i.connect(g)
};
this.onConnect = function() {
f.log("Spotify.WebSockets.Bridge", ["[State.connecting] Socket connected"], "corejs");
o(2)
};
this.onDisconnect = function() {
f.log("Spotify.WebSockets.Bridge", ["[State.connecting] Socket disconnected"], "corejs");
b.trigger(c.FAILED_CONNECTING, {});
o(0)
};
this.disconnect = function() {
i.disconnect()
};
this.onError = function(a) {
f.error("Spotify.WebSockets.Bridge", ["[State.connecting] Error", a], "corejs");
b.trigger(c.FAILED_CONNECTING, {});
o(0)
}
};
k[2] = new
function() {
n.call(this);
this.activate = function() {
f.log("Spotify.WebSockets.Bridge", ["[State.authorizing] Sending auth object"], "corejs");
clearInterval(m);
var b = a.split(":");
if (parseInt(b[0], 10) > 200) var c = b.shift(),
g = b.shift(),
b = b.join(":"),
b = [c, g, b];
i.sendObject({
name: "connect",
id: "0",
args: b
})
};
this.disconnect = function() {
i.disconnect()
};
this.onDisconnect = function() {
f.log("Spotify.WebSockets.Bridge", ["[State.authorizing] Socket disconnected"], "corejs");
b.trigger(c.FAILED_CONNECTING, {});
o(0)
};
this.onMessage = function(a) {
f.log("Spotify.WebSockets.Bridge", ["[State.authorizing] Got message", a], "corejs");
try {
var g = JSON.parse(a);
g.result === "ok" ? (b.trigger(c.AUTHENTICATED, {}), b.trigger(c.CONNECTION_ESTABLISHED, {}), o(3)) : g.error && (b.trigger(c.FAILED_CONNECTING, {}), b.disconnect(), o(0))
} catch (i) {}
}
};
k[3] = new
function() {
n.call(this);
this.activate = function() {
clearInterval(m);
m = setInterval(function() {
i.isConnected() || (clearInterval(m), i.trigger("ondisconnect"))
}, 1E3)
};
this.onMessage = function(a) {
f.log("Spotify.WebSockets.Bridge", ["[State.authorized] Got message", a], "corejs");
try {
var g = JSON.parse(a),
i = g.message ? g.message[0] : null;
i === "token_lost" ? b.trigger(c.TOKEN_LOST, {}) : i === "do_work" ? b.trigger(c.WORK, g.message[1]) : i === "login_complete" ? b.trigger(c.LOGIN_COMPLETE) : i === "hm_b64" ? b.trigger(c.HERMES_B64_MESSAGE, g.message) : i === "user_info_change" ? b.trigger(c.USER_INFO_CHANGE) : g.id ? g.error ? b.trigger(c.RPC_ERRBACK, {
requestId: g.id,
response: g.error
}) : b.trigger(c.RPC_CALLBACK, {
requestId: g.id,
response: g.result
}) : b.trigger(c.ERROR, {
error: "Response object invalid"
})
} catch (d) {
b.trigger(c.ERROR, {
message: "Response not a JSON object"
})
}
};
this.disconnect = function() {
i.disconnect()
};
this.onDisconnect = function() {
f.log("Spotify.WebSockets.Bridge", ["[State.authorized] Socket disconnected"], "corejs");
b.trigger(c.FAILED_CONNECTING, {});
o(0)
};
this.rpc = function(a, b, c) {
f.log("Spotify.WebSockets.Bridge", ["[State.authorized] Doing an RPC call", a, b], "corejs");
i.sendObject({
id: c,
name: "sp/" + a,
args: b
})
};
this.onError = function(a) {
f.error("Spotify.WebSockets.Bridge", ["[State.authorized] onerror", a], "corejs")
}
};
this.rpc = function(a, b, c) {
l.rpc(a, b, c)
};
this.connect = function(b, c) {
b && (a = b);
c && (g = c);
l.connect()
};
this.disconnect = function() {
l.disconnect()
};
this.initialize = function() {
if (g === "") throw Error("Spotify.WebSockets.Bridge connectionUri cannot be empty");
i = new Spotify.WebSockets.Client;
i.bind("onconnect", function() {
l.onConnect()
});
i.bind("ondisconnect", function() {
l.onDisconnect()
});
i.bind("onmessage", function(a) {
l.onMessage(a.params.message)
});
i.bind("onerror", function(a) {
l.onError(a.params.message)
});
b.trigger(c.READY, {});
o(0)
}
};
Spotify.WebSockets.Client = function() {
Spotify.EventTarget.call(this);
var d = Spotify.DebuggerJS,
h = null,
f = this;
this.connect = function(b) {
if (b === "") throw Error("Core.WebSockets.Client connection Uri was not set");
if (this.isConnected()) return !1;
if (WebSocket === void 0) throw Error("Core.WebSockets.Client WebSocket interface not supported");
var c = this.currentConnection = (this.currentConnection || 0) + 1;
h = new WebSocket(b);
h.onopen = function() {
d.log("Spotify.WebSockets.Client", ["onopen", c], "corejs");
c == f.currentConnection && f.trigger("onconnect", {})
};
h.onclose = function() {
d.log("Spotify.WebSockets.Client", ["onclose", c], "corejs");
c == f.currentConnection && f.trigger("ondisconnect", {})
};
h.onmessage = function(a) {
d.log("Spotify.WebSockets.Client", ["onmessage", a, c], "corejs");
c == f.currentConnection && f.trigger("onmessage", {
message: a.data
})
};
h.onerror = function(a) {
d.error("Spotify.WebSockets.Client", ["onerror", a, c], "corejs");
c == f.currentConnection && f.trigger("onerror", {
message: a
})
}
};
this.disconnect = function() {
if (!this.isConnected()) throw Error("Core.WebSocket.Client not connected");
h.close();
h = null;
f.trigger("ondisconnect", {})
};
this.isConnected = function() {
return h && h.readyState === 1
};
this.send = function(b) {
this.isConnected() ? h.send(b) : (f.trigger("ondisconnect", {}), log("Core.WebSocket.Client not connected"))
};
this.sendObject = function(b) {
var c = JSON.stringify(b);
c.length > 32768 ? f.trigger("onmessage", {
message: JSON.stringify({
id: b.id,
error: [16, 1, "PACKET_SIZE_EXCEEDED"]
})
}) : this.send(c)
}
};
Spotify.EventTarget = function() {
this._listeners = {};
this.bind = function(h, f, b, c) {
typeof c === "undefined" && (c = 0);
if (typeof f !== "undefined" && f !== null) {
var c = {
callback: f,
context: b,
priority: c
},
a = !1,
g;
this._listeners[h] === void 0 && (this._listeners[h] = []);
g = this._listeners[h];
for (var i = 0; i < g.length; i++) if (g[i].callback === f && g[i].context === b) {
a = !0;
break
}
a === !1 && (this._listeners[h].push(c), this._listeners[h].sort(d))
}
};
var d = function(d, f) {
return f.priority - d.priority
};
this.trigger = function(d, f) {
var b = this._listeners[d],
f = f || {};
if (typeof b !== "undefined") for (var c = 0; c < b.length; c++) {
var a = b[c];
setTimeout(a.callback.bind(a.context, {
type: d,
params: f
}), 15)
}
};
this.unbind = function(d, f, b) {
var c = -1,
a = this._listeners[d];
if (typeof f !== "undefined") {
if (typeof a !== "undefined") {
for (var g = 0; g < a.length; g++) if (a[g].callback === f && a[g].context === b) {
c = g;
break
}
c !== -1 && this._listeners[d].splice(c, 1)
}
} else this._listeners[d] = []
}
};
Spotify.Protobuf.Schema = function(d, h, f, b) {
Spotify.EventTarget.call(this);
var c, a = 0,
g = [];
this.id = "";
this.PROTO = "proto";
this.type = this.JSON = "json";
this.load = function() {
var b, c;
if (this.type === this.JSON) c = "json";
else if (this.type === this.PROTO) c = "text";
else
throw Error("Not a valid descriptor file for the protobuf schema");
for (b = a = 0; b < d.length; b++) if (typeof d[b] === "string") {
a++;
var g = new Spotify.Service;
g.url = d[b];
g.dataType = c;
g.bind("onSuccess", this.done, this);
g.bind("onError", this.error, this);
g.fetch()
}
};
this.reset = function() {
g = null
};
this.getSchema = function() {
return c
};
this.msg = function(a) {
return c[a]
};
this.parse = function(a) {
g = g === null ? a : g.concat(a)
};
this.encode = function() {
var a;
this.type == this.JSON ? c = Spotify.Protobuf.Serialization.createFromJson(g) : (a = Spotify.Protobuf.Parser.parseFileDescriptor(g), c = Spotify.Protobuf.Serialization.createFromFileDescriptor(a))
};
this.done = function(c) {
this.parse(c.params.result);
a--;
a === 0 && (this.encode(), typeof b !== "undefined" ? typeof h !== "undefined" && h.call(b, this.id) : typeof h !== "undefined" && h(this.id))
};
this.setData = function(a) {
g = a
};
this.error = function(a) {
typeof b !== "undefined" ? typeof f !== "undefined" && f.call(b, a) : typeof f !== "undefined" && f(a)
}
};
(function() {
var d;
Spotify.Events = function() {
return typeof d !== "undefined" ? d : d = {
DATA_ERROR: "DATA_ERROR",
TRACK_PLAY_REQUEST: "TRACK_PLAY_REQUEST",
WAIT_FOR_COMMERCIAL_TO_FINISH: "WAIT_FOR_COMMERCIAL_TO_FINISH",
INTERCEPTED: "intercepted",
USER_INFO_CHANGE: "USER_INFO_CHANGE",
TRACK_ENDED: "TRACK_ENDED",
ON_LOAD: "ON_LOAD",
SONG_LOADED: "SONG_LOADED",
FIRST_BYTES: "FIRST_BYTES",
POSITION_CHANGED: "POSITION_CHANGED",
VOLUME_CHANGED: "VOLUME_CHANGED",
PLAYING: "PLAYING",
PAUSED: "PAUSED",
STOPPED: "STOPPED",
CONNECTION_ESTABLISHED: "CONNECTION_ESTABLISHED",
CONNECTION_CLOSED: "CONNECTION_CLOSED",
CONNECTED: "CONNECTED",
DISCONNECTED: "DISCONNECTED",
STREAM_INITIALIZED: "STREAM_INITIALIZED",
PLAYER_LOADED: "PLAYER_LOADED",
STREAM_LIMIT_REACHED: "STREAM_LIMIT_REACHED",
AUTHENTICATED: "AUTHENTICATED",
ERROR: "ERROR",
SUCCESS: "SUCCESS",
FAILED_CONNECTING: "FAILED_CONNECTING",
INVALID_TRACK_URI: "INVALID_TRACK_URI",
CANNOT_PLAY_TRACK: "CANNOT_PLAY_TRACK",
INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
REGION_BLOCKED: "REGION_BLOCKED",
ACCOUNT_IN_USE: "ACCOUNT_IN_USE",
PLAYBACK_FAILED: "PLAYBACK_FAILED",
SECURITY_ERROR: "SECURITY_ERROR",
UNKNOWN_ERROR: "UNKNOWN_ERROR",
RPC_CALLBACK: "RPC_CALLBACK",
RPC_ERRBACK: "RPC_ERRBACK",
RPC_LOGGING_LATENCY_CALLBACK: "RPC_LOGGING_LATENCY_CALLBACK",
RPC_LOGGING_LATENCY_ERRBACK: "RPC_LOGGING_LATENCY_ERRBACK",
RPC_SUCCESS: "RPC_SUCCESS",
RPC_ERROR: "RPC_ERROR",
REAUTHORIZE_SUCCESS: "REAUTHORIZE_SUCCESS",
REAUTHORIZE_FAILED: "REAUTHORIZE_FAILED",
FLASH_LOADED: "FLASH_LOADED",
FLASH_UNAVAILABLE: "FLASH_UNAVAILABLE",
FLASH_AVAILABLE: "FLASH_AVAILABLE",
READY: "READY",
TOKEN_ACQUIRED: "TOKEN_ACQUIRED",
TOKEN_NOT_ACQUIRED: "TOKEN_NOT_ACQUIRED",
ON_TRY_TO_CONNECT: "ON_TRY_TO_CONNECT",
NOTIFY_OF_DISCONNECT: "NOTIFY_OF_DISCONNECT",
FATAL_ERROR: "FATAL_ERROR",
TOKEN_LOST: "TOKEN_LOST",
WORK: "WORK",
LOGIN_COMPLETE: "LOGIN_COMPLETE",
HERMES_B64_MESSAGE: "HERMES_B64_MESSAGE",
TIMEOUT: "TIMEOUT",
NO_SOUND_CAPABILITIES: "NO_SOUND_CAPABILITIES",
ON_REAUTHENTICATION_SUCCESS: "ON_REAUTHENTICATION_SUCCESS",
ON_REAUTHENTICATION_FAILED: "ON_REAUTHENTICATION_FAILED",
STORAGE_FULL: "STORAGE_FULL",
RATE_LIMIT_CALL: "RATE_LIMIT_CALL",
RATE_LIMIT_DISABLED: "RATE_LIMIT_DISABLED",
REMOTE_CONTROL_STARTED: "REMOTE_CONTROL_STARTED",
REMOTE_CONTROL_STOPPED: "REMOTE_CONTROL_STOPPED",
DEVICE_DISCOVERED: "DEVICE_DISCOVERED",
DEVICE_REMOVED: "DEVICE_REMOVED",
REMOTE_COMMAND: "REMOTE_COMMAND",
REMOTE_SERVICE_DOWN: "REMOTE_SERVICE_DOWN",
NOTIFICATION: "NOTIFICATION",
RELATIONS_SUBSCRIBE: "RELATIONS_SUBSCRIBE",
RELATIONS_UNSUBSCRIBE: "RELATIONS_UNSUBSCRIBE"
}
}
})();
Spotify.Hermes.Cache = new
function() {
var d = Spotify.Cache.Default,
h = this,
f = [null, null],
b = function() {
return JSON.parse(localStorage.getItem("com.spotify.cache.indexeddb") || !1)
},
c = function() {
return f[d.TEMPORARY] != null && f[d.PERSISTENT] != null
},
a = function(a) {
return function(b) {
var g = "com.spotify.cache." + a + ".version",
i = function() {
localStorage.setItem(g, (2).toString());
f[a] = b;
c() && h.trigger(Spotify.Events.READY)
};
parseInt(localStorage.getItem(g)) != 2 ? b.clear(i) : i()
}
},
g = function() {
throw Error("Failed creating caches!");
},
i = function(a) {
return a.indexOf("hm://playlist/") == 0 ? f[d.PERSISTENT] : f[d.TEMPORARY]
},
n = function(a, b, c, g, d, f) {
var h = i(a);
h.get(b, function(a, b) {
b == null ? g.call(f) : b.expires < (new Date).getTime() ? b.etag ? d.call(f, b.frames, b.etag) : (h.remove(a), g.call(f)) : c.call(f, b.frames)
})
};
h.onReady = function(a, b) {
c() ? a.call(b) : h.bind(Spotify.Events.READY, a, b)
};
h.getCacheKey = function(a) {
for (var b = [a.getURI()], c = 0, g = a.getRequestFrameCount(); c < g; ++c) b.push(a.getRequestFrame(c));
return b.join("")
};
h.getCachedFrames = function(a, b, g, i, d, f) {
c() ? n(a, b, g, i, d, f) : i.call(f)
};
h.setCachedFrames = function(a, b, g, d, f, n) {
if (c() && d && (g == "CACHE_PRIVATE" || g == "CACHE_PUBLIC")) {
g = {
frames: n,
expires: (new Date).getTime() + d * 1E3
};
if (f) g.etag = f;
i(a).put(b, g, null, null, h.onfull)
}
};
h.onfull = function() {};
h.migrateToIndexedDB = function(a, c, g) {
if (b()) a.call(g);
else {
var i = f[d.PERSISTENT],
h = new d(5E3, new Spotify.Cache.IndexedDBStorage("Spotify.Mercury.Cache"));
delete f[d.PERSISTENT];
var n = function(a, b) {
h.put(a, b)
},
s = function() {
f[d.PERSISTENT] = h;
i.clear();
localStorage.setItem("com.spotify.cache.indexeddb", "true");
a.call(g, this)
};
h.initialize(function() {
i._storage.each(n, s, this)
}, c, g)
}
};
(function() {
Spotify.EventTarget.call(h);
var c = new d(500, new Spotify.Cache.MemoryStorage("Spotify.Mercury.Cache"));
c.initialize(a(d.TEMPORARY), g);
c = b() ? new d(5E3, new Spotify.Cache.IndexedDBStorage("Spotify.Mercury.Cache")) : new d(5E3, new Spotify.Cache.LocalStorage("Spotify.Mercury.Cache"));
c.initialize(a(d.PERSISTENT), g)
})()
};
(function() {
if (typeof window.btoa !== "function") window.btoa = Spotify.Utils.Base64.encode;
if (typeof window.atob !== "function") window.atob = Spotify.Utils.Base64.decode;
var d = Spotify.DebuggerJS,
h = Spotify.Protobuf.Serialization.createFromJson([{
name: "Header",
fields: [{
id: 1,
type: "string",
name: "uri"
}, {
id: 2,
type: "string",
name: "content_type"
}, {
id: 3,
type: "string",
name: "method"
}, {
id: 4,
type: "sint32",
name: "status_code"
}, {
id: 5,
type: "string",
name: "source"
}, {
id: 6,
type: "*UserField",
name: "user_fields"
}]
}, {
name: "UserField",
fields: [{
id: 1,
type: "string",
name: "name"
}, {
id: 2,
type: "bytes",
name: "value"
}]
}]).Header,
f = Spotify.Hermes.Cache;
Spotify.Hermes.Header = h;
Spotify.Hermes.Request = function(b) {
if (b.uri == void 0) throw Error("URI not specified!");
this.getURI = function() {
return b.uri
};
this.getRequestFrameCount = function() {
return 0
};
this.getRequestFrameData = function() {
return null
};
this.setRequestFrameData = function() {};
this.getRequestFrame = function() {
return null
};
this.parseResponseFrame = function(a, b) {
return b
};
var c = function(a) {
for (var b = [], c = (new Date).getTime(), g = 1, i = a.length; g < i; ++g) b.push(this.parseResponseFrame(g - 1, a[g]));
d.log("Spotify.Hermes.Request", ["It took", (new Date).getTime() - c, "ms to parse the frames"], "parsing_times");
return b
},
a = function(a) {
for (var b = [], c = 0, g = a.length; c < g; ++c) b.push(window.atob(a[c]));
return b
},
g = function(a) {
var b = {};
if (a.user_fields) for (var c = 0, g = a.user_fields.length; c < g; ++c) {
var i = a.user_fields[c];
switch (i.name) {
case "MC-Cache-Policy":
if (i.value == "private") b.cache_policy = "CACHE_PRIVATE";
else if (i.value == "public") b.cache_policy = "CACHE_PUBLIC";
break;
case "MC-TTL":
b.ttl = i.value;
break;
case "MC-ETag":
b.etag = i.value
}
}
return b
},
i = function(a, b, c) {
a.user_fields = a.user_fields || [];
a.user_fields.push({
name: b,
value: c
})
},
n = function(i, l, n, o, m, w, v) {
o != null && m != null ? b.user_fields = [{
name: "MC-ETag",
value: m
}] : delete b.user_fields;
var t;
a: {
switch (b.method) {
case "SUB":
t = 1;
break a;
case "UNSUB":
t = 2;
break a
}
t = 0
}
m = (new Date).getTime();t = [t, window.btoa(h.serializeToStringSync(b))];
for (var y = 0, C = this.getRequestFrameCount(); y < C; ++y) t.push(window.btoa(this.getRequestFrame(y)));d.log("Spotify.Hermes.Request", ["It took", (new Date).getTime() - m, "ms to serialize the request"], "parsing_times");i.rpc("hm_b64", t, function(b) {
var b = a(b.response),
i = h.parseFromStringSync(b[0]),
d = i.status_code;
d >= 200 && d <= 299 ? (i = g(i), f.setCachedFrames(this.getURI(), f.getCacheKey(this), i.cache_policy, i.ttl, i.etag, b), l(c.call(this, b), d)) : d == 304 ? l(c.call(this, o), d) : n(new Spotify.Errors.Error([13, d]))
}, n, this, w || !1, 2, v)
},
l = function(a) {
if (a.length != 2) throw Error("Invalid number of frames!");
var b = h.parseFromStringSync(a[0]),
a = {
content_type: b.content_type,
status_code: b.status_code,
body: a[1]
},
b = g(b),
c;
for (c in b) a[c] = b[c];
return a
},
m = function(a, b) {
var c = {
uri: b,
content_type: a.content_type,
status_code: a.status_code
};
a.cache_policy == "CACHE_PUBLIC" ? i(c, "MC-Cache-Policy", "public") : a.cache_policy == "CACHE_PRIVATE" && i(c, "MC-Cache-Policy", "private");
a.ttl !== void 0 && i(c, "MC-TTL", a.ttl);
a.etag !== void 0 && i(c, "MC-ETag", a.etag);
return [h.serializeToStringSync(c), a.body]
},
o = function(c, g, i, n, o, w) {
o = typeof o !== "undefined" ? o : !1;
if (this.getRequestFrameCount() != 1) throw Error("Invalid number of request frames!");
var v = this.getRequestFrameData(0).request,
t = v.length,
y = [],
C = [],
x = Array(t),
z = function(b) {
var c = a(b.response),
k = h.parseFromStringSync(c[0]),
b = k.status_code;
if (Spotify.Hermes.Request.isSuccess(b)) if (k.content_type != "vnd.spotify/mercury-mget-reply") i(new Spotify.Errors.Error([Spotify.Errors.Domains.HERMES_ERROR, 500, "Server didn't send a multi-GET reply!"]));
else if (c.length != 2) i(new Spotify.Errors.Error([Spotify.Errors.Domains.HERMES_ERROR, 500, "Invalid number of frames in multi-GET reply!"]));
else {
for (var c = this.parseResponseFrame(0, c[1]).reply, k = (new Date).getTime(), n = 0, o = c.length; n < o; ++n) {
var s = y[n],
t = c[n],
v = C.shift();
t.status_code == 304 ? (x[v] = l(s.cachedFrames), x[v].status_code = 200) : Spotify.Hermes.Request.isSuccess(t.status_code) ? (x[v] = t, f.setCachedFrames(s.uri, s.uri + (s.body || ""), t.cache_policy, t.ttl, t.etag, m(t, s.uri))) : delete x[v]
}
d.log("Spotify.Hermes.Request", ["It took", (new Date).getTime() - k, "ms to parse the frames"], "parsing_times");
g([{
reply: x
}], b)
} else i(new Spotify.Errors.Error([Spotify.Errors.Domains.HERMES_ERROR, b]))
},
B = function() {
if (y.length == 0) g([{
reply: x
}], 200);
else {
var a = (new Date).getTime(),
f = [0, window.btoa(h.serializeToStringSync(b))];
this.setRequestFrameData(0, {
request: y
});
f.push(window.btoa(this.getRequestFrame(0)));
d.log("Spotify.Hermes.Request", ["It took", (new Date).getTime() - a, "ms to serialize the request"], "parsing_times");
c.rpc("hm_b64", f, z, i, this, n || !1, 2, w)
}
},
M = function(a) {
return function(b) {
x[a] = l(b);
--t <= 0 && B.call(this)
}
},
H = function(a) {
return function() {
y.push(v[a]);
C.push(a);
--t <= 0 && B.call(this)
}
},
E = function(a) {
return function(b, c) {
v[a].etag = c;
v[a].cachedFrames = b;
y.push(v[a]);
C.push(a);
--t <= 0 && B.call(this)
}
};
if (o) for (var o = 0, F = v.length; o < F; ++o) H(o).call(this);
else {
o = 0;
for (F = v.length; o < F; ++o) {
var D = v[o];
f.getCachedFrames(D.uri, D.uri + (D.body || ""), M(o), H(o), E(o), this)
}
}
};
this.send = function(a, g, i, d, l, h) {
l = typeof l !== "undefined" ? l : !1;
if (b.content_type == "vnd.spotify/mercury-mget-request") o.call(this, a, g, i, d, l, h);
else {
var m = function(a) {
g(c.call(this, a), 200)
},
t = function() {
n.call(this, a, g, i, null, null, d, h)
},
y = function(b, c) {
n.call(this, a, g, i, b, c, d, h)
};
l ? t.call(this) : f.getCachedFrames(this.getURI(), f.getCacheKey(this), m, t, y, this)
}
}
};
Spotify.Hermes.Request.isSuccess = function(b) {
return b >= 200 && b < 300
};
Spotify.Hermes.Request.isRedirect = function(b) {
return b >= 300 && b < 400
};
Spotify.Hermes.Request.isClientError = function(b) {
return b >= 400 && b < 500
};
Spotify.Hermes.Request.isServerError = function(b) {
return b >= 500 && b < 600
};
Spotify.Hermes.StringRequest = function(b, c) {
var a = new Spotify.Hermes.Request(b);
a.getRequestFrameCount = function() {
return c.length
};
a.getRequestFrameData = function(a) {
return c[a]
};
a.setRequestFrameData = function(a, b) {
c[a] = b
};
a.getRequestFrame = function(a) {
return c[a]
};
a.parseResponseFrame = function(a, b) {
return b
};
return a
};
Spotify.Hermes.ProtobufRequest = function(b, c, a, g) {
b = new Spotify.Hermes.Request(b);
b.getRequestFrameCount = function() {
return c.length
};
b.getRequestFrameData = function(a) {
return c[a]
};
b.setRequestFrameData = function(a, b) {
c[a] = b
};
b.getRequestFrame = function(b) {
return a[b] ? a[b].serializeToStringSync(c[b]) : c[b]
};
b.parseResponseFrame = function(a, b) {
return a < g.length ? g[a].parseFromStringSync(b) : b
};
return b
}
})();
Spotify.Hermes.Handler = function() {
Spotify.EventTarget.call(this);
var d = {},
h, f = function(b) {
var c;
if (typeof b !== void 0 && (c = b.split("#"), Spotify.Utils.isArray(c) && c.length == 2)) return b = c[0], c = c[1], typeof d[b] !== "undefined" ? d[b].msg(c) : null;
throw Error("Not a valid message!");
};
this.send = function(b, c, a, g, i, d, l, m, o) {
var m = m || !1,
k = [],
p = [];
if (!Spotify.Utils.isArray(a) && !Spotify.Utils.isArray(g)) throw "Hermes:send Wrong arguments";
for (var q = 0; q < a.length; q++) k.push(f(a[q]));
for (q = 0; q < g.length; q++) p.push(f(g[q]));
(new Spotify.Hermes.ProtobufRequest({
uri: b,
method: c
}, i, k, p)).send(h, d, l, m, o, "hermes")
};
this.loadSchemas = function(b, c, a, g) {
var i;
if (Spotify.Utils.isArray(b)) if (i = Spotify.Utils.Base64.encode(b.join("_")) + "_", typeof d[i] !== "undefined") a(i);
else
try {
var f = new Spotify.Protobuf.Schema(b, a, g, null);
d[i] = f;
if (c !== f.PROTO && c !== f.JSON) c = f.JSON;
f.id = i;
f.type = c;
f.reset();
f.load()
} catch (l) {
throw typeof g !== "undefined" && g(l), l;
} else g(Error("Schemas is not an array"))
};
this.loadSchemaData = function(b, c, a) {
var g = (new Date).getTime() + Math.floor(Math.random() * 1E3),
g = Spotify.Utils.Base64.encode(g.toString()) + "_",
i, f;
if (Spotify.Utils.isArray(b)) {
b = b.join("\n");
for (i in d) a = d[i], a === b[0] && (f = a, g = i);
if (typeof f === "undefined") f = new Spotify.Protobuf.Schema([], null, null, null), f.id = g, f.type = "proto", f.setData(b), f.encode(), d[g] = f;
c(g)
} else a(Error("Schemas is not an array"))
};
this.init = function(b) {
h = b
}
};
Spotify.GatewayTypes = {
FLASH: "FLASH",
WEBSOCKETS: "WEBSOCKETS"
};
Spotify.PlayerTypes = {
FLASH_RTMPS: "FLASH_RTMPS",
FLASH_HTTP: "FLASH_HTTP",
FLASH_AAC: "FLASH_AAC",
WEBSOCKETS_STREAMING: "WEBSOCKETS_STREAMING",
HTML5_HTTP: "HTML5_HTTP"
};
Spotify.Protocols = {
RTMPS: "RTMPS",
RTMP: "RTMP",
HTTP: "HTTP",
HTTPS: "HTTPS"
};
Spotify.Instances = function() {
var d = {};
return {
add: function(h) {
h.id = "SPFBIn_" + Math.floor(Math.random() * 1E4);
d[h.id] = h;
return !0
},
get: function(h) {
if (typeof d[h] !== void 0) return d[h]
}
}
}();
Spotify.Flash.SWFObject = function(d) {
Spotify.EventTarget.call(this);
var h = Spotify.DebuggerJS,
f = this;
this.isLoaded = !1;
var b = new Spotify.Events;
this.getSWF = function() {
if (this.isLoaded) {
if (window.document[d.SWFFlashId]) return window.document[d.SWFFlashId];
if (navigator.appName.indexOf("Microsoft Internet") === -1) {
if (document.embeds && document.embeds[d.SWFFlashId]) return document.embeds[d.SWFFlashId]
} else
return document.getElementById(d.SWFFlashId)
} else h.error("Spotify.Flash.SWFObject", ["SWF Object is not loaded...."], "corejs")
};
this.initialize = function() {
swfobject.hasFlashPlayerVersion(d.SWFMinVersion) ? swfobject.embedSWF(d.SWFUrl, d.SWFContainerId, "1", "1", d.SWFMinVersion, "", {
playerType: d.playerType,
valid: 0,
id: d.SWFFlashId || "",
length: 0,
instanceId: d.instanceId,
logging: d.logging,
authUrl: d.authUrl
}, {
quality: "high",
allowscriptaccess: "always",
wmode: "window",
bgcolor: "#2c2c2d"
}, {
id: d.SWFFlashId,
name: d.SWFFlashId,
align: "middle"
}, c) : h.error("Spotify.Flash.SWFObject", ["Your Flash is not up to date: " + d.SWFMinVersion], "corejs")
};
var c = function(a) {
!1 === a.success ? (f.trigger(b.FLASH_UNAVAILABLE), h.error("Spotify.Flash.SWFObject", ["Cannot load SWF object"], "corejs")) : (f.trigger(b.FLASH_AVAILABLE), f.isLoaded = !0)
}
};
Spotify.Flash.Player = function(d) {
Spotify.EventTarget.call(this);
var h = Spotify.DebuggerJS,
f = this,
b = new Spotify.Events,
c = "",
a = d.flashObject,
g = 0,
i = !1,
n = 0,
l = 0,
m = 0,
o = !1;
this.dataForLoggingOnPlay = {};
this.lid = "";
this.isAd = !1;
this.trackUrl = this.trackUri = "";
this.bitrate = 160;
this.audiocodec = "mp3";
this.isPaused = this.isPlaying = !1;
this.isStopped = !0;
this.isMuted = this.isLoaded = !1;
this.adUriResolver = this.songUriResolver = null;
this.hasSoundCapabilities = !0;
this.isReady = !1;
this.playpause = function() {
if (typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities) this.isPaused = a.getSWF().sp_playpause()
};
this.position = function() {
try {
if (typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities) return m = a.getSWF().sp_time()
} catch (b) {
return 0
}
};
this.getPlayerState = function() {
var b = {
volume: 0,
position: 0,
duration: 0
};
typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities && (b = a.getSWF().sp_playerState());
n = b.volume;
m = b.position;
l = b.duration;
b.isPlaying = this.isPlaying;
b.isStopped = this.isStopped;
b.isPaused = this.isPaused;
return b
};
this.seek = function(b) {
if (typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities) return a.getSWF().sp_seek(b)
};
this.pause = function() {
typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities && a.getSWF().sp_pause()
};
this.resume = function() {
typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities && a.getSWF().sp_resume()
};
this.stop = function() {
o && (o = !1, typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities && a.getSWF().sp_stop())
};
this.load = function(a, d, f) {
var l = new Spotify.Link.fromString(a);
this.trigger(b.TRACK_PLAY_REQUEST, {
timestamp: (new Date).getTime()
});
g = d || 0;
i = typeof f === "undefined" ? !1 : f;
c = a;
if (this.isAd = l.type === "ad" ? !0 : !1) this.adUriResolver.onReady(function() {
try {
this.adUriResolver.list(a, k, p)
} catch (b) {
h.error("Spotify.Flash.Player", [b.message, b.stack], "corejs")
}
}, this);
else this.songUriResolver.onReady(function() {
try {
this.songUriResolver.list(a, k, p)
} catch (b) {
h.error("Spotify.Flash.Player", [b.message, b.stack], "corejs")
}
}, this)
};
var k = function(b) {
f.lid = b.lid;
f.trackUrl = b.uri;
f.trackUri = c;
o = !0;
typeof a !== "undefined" && a.isLoaded && f.hasSoundCapabilities && (a.getSWF().sp_load(f.trackUrl), i && (f.play(g), i = !1, g = 0))
},
p = function(a) {
o = !1;
f.lid = "";
f.trackUrl = "";
c = f.trackUri = "";
g = 0;
f.trigger(b.INVALID_TRACK_URI, a)
};
this.play = function(b) {
typeof a !== "undefined" && a.isLoaded && f.hasSoundCapabilities && a.getSWF().sp_play(b)
};
this.setVolume = function(b) {
if (typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities && !isNaN(b) && b >= 0 && b <= 1) {
n = b;
try {
a.getSWF().sp_setVolume(b)
} catch (c) {}
}
};
this.getVolume = function() {
if (typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities) try {
n = a.getSWF().sp_getVolume()
} catch (b) {}
return n
};
this.getDuration = function() {
if (typeof a !== "undefined" && a.isLoaded && this.hasSoundCapabilities) try {
l = a.getSWF().sp_getDuration()
} catch (b) {}
return l
};
this.hasSound = function() {
return typeof a !== "undefined" && a.isLoaded ? this.hasSoundCapabilities = a.getSWF().sp_hasSound() : !1
};
this.initialize = function() {
this.bind(b.READY, q, this)
};
var q = function() {
f.hasSound() || f.trigger(b.NO_SOUND_CAPABILITIES)
};
this.onLoad = function() {};
this.onPlay = function() {};
this.onPause = function() {};
this.onStop = function() {};
this.onTrackEnded = function() {};
this.onSongLoaded = function() {};
this.onPositionChanged = function() {};
this.onInvalidTrackUri = function() {};
this.onPlaybackFailed = function() {}
};
Spotify.HTML5.Player = function(d) {
Spotify.EventTarget.call(this);
var h = Spotify.DebuggerJS,
f = this,
b = new Spotify.Events,
c, a = !1,
g = 0,
i = 0,
n = !1,
l = !1;
this.dataForLoggingOnPlay = {};
this.lid = "";
this.isAd = !1;
this.trackUrl = this.trackUri = "";
this.bitrate = 160;
this.audiocodec = "mp3";
this.isPlaying = !1;
this.isStopped = this.isPaused = !0;
this.isMuted = !1;
this.adUriResolver = this.songUriResolver = this.context = null;
this.hasSoundCapabilities = !0;
this.playpause = function() {
l && n && (this.isPaused ? this.resume() : this.isPlaying && this.pause())
};
this.position = function() {
if (!l || !n) return 0;
i = c.currentTime;
return p()
};
this.getPlayerState = function() {
var a = {};
a.position = c.currentTime * 1E3;
a.volume = g;
a.duration = 0;
a.isPlaying = this.isPlaying;
a.isStopped = this.isStopped;
a.isPaused = this.isPaused;
return a
};
this.seek = function(a) {
if (l && n) i = c.currentTime = a / 1E3, this.trigger(b.POSITION_CHANGED, p())
};
this.pause = function() {
if (l && n && this.isPlaying) c.pause(), i = c.currentTime, this.trigger(b.PAUSED, p())
};
this.resume = function() {
l && n && this.isPaused && this.play(i)
};
this.stop = function() {
l && n && (c.pause(), i = 0, n = !1, this.trigger(b.STOPPED))
};
this.load = function(c, g, i) {
if (l) if (g = new Spotify.Link.fromString(c), this.trigger(b.TRACK_PLAY_REQUEST, {
timestamp: (new Date).getTime()
}), a = typeof i === "undefined" ? !1 : i, _tempTrackUri = c, this.isAd = g.type === "ad" ? !0 : !1) this.adUriResolver.onReady(function() {
try {
this.adUriResolver.list(c, m, o)
} catch (a) {
h.error("Spotify.HTML5.Player", [a.message, a.stack], "corejs")
}
}, this);
else this.songUriResolver.onReady(function() {
try {
this.songUriResolver.list(c, m, o)
} catch (a) {
h.error("Spotify.HTML5.Player", [a.message, a.stack], "corejs")
}
}, this)
};
var m = function(g) {
f.lid = g.lid;
f.trackUrl = g.uri;
f.trackUri = _tempTrackUri;
n = !0;
f.isPlaying && f.stop();
c.setAttribute("type", "audio/mp3");
c.src = f.trackUrl;
f.trigger(b.ON_LOAD);
a && f.play();
n = !0;
a = !1
},
o = function(a) {
n = !1;
f.lid = "";
f.trackUrl = "";
_tempTrackUri = f.trackUri = "";
f.trigger(b.INVALID_TRACK_URI, a)
},
k = function(a) {
a.type === "ended" && f.trigger(b.TRACK_ENDED)
},
p = function() {
return Math.floor(i * 1E3)
};
this.play = function(a) {
if (l && n) {
try {
c.currentTime = a
} catch (g) {}
i = a;
c.play();
f.trigger(b.PLAYING, p())
}
};
this.setVolume = function(a) {
if (!isNaN(a) && a >= 0 && a <= 1 && (g = a, l && n)) c.volume = g
};
this.getVolume = function() {
return g
};
this.getDuration = function() {
return !l || !n ? 0 : Math.floor(c.duration * 1E3)
};
this.initialize = function() {
if (typeof d === "undefined") throw new Event("Not a valid id for the audio tag");
c = document.createElement("audio");
document.getElementById(d).appendChild(c);
c.innerHtml = '<source src="" type="audio/mp3"></source>';
c.addEventListener("ended", k);
l = !0;
this.trigger(b.READY)
};
this.onLoad = function() {};
this.onPlay = function() {};
this.onPause = function() {};
this.onStop = function() {};
this.onTrackEnded = function() {};
this.onSongLoaded = function() {};
this.onPositionChanged = function() {};
this.onInvalidTrackUri = function() {};
this.onPlaybackFailed = function() {}
};
Spotify.Parsers.Metadata = function() {
var d = Spotify.Utils,
h = function(a, b) {
return a == "premium" && b.catalogue == "premium" ? !0 : a == "available"
},
f = function(a, b) {
for (var c = 0, g = b.length; c < g; c += 2) if (a[0] == b[c] && a[1] == b[c + 1]) return !0;
return !1
},
b = function(c, f) {
if (c.gid != void 0) c.id = d.str2hex(c.gid), delete c.gid;
if (c.artist != void 0) for (var m = 0, o = c.artist.length; m < o; ++m) c.artist[m] = a(c.artist[m], null);
if (c.disc != void 0) {
m = 0;
for (o = c.disc.length; m < o; ++m) {
var k = c.disc,
p = m,
q = c.disc[m];
if (q.track != void 0) for (var s = 0, u =
q.track.length; s < u; ++s) q.track[s] = i(q.track[s], null);
k[p] = q
}
}
if (f != null) c.availability = g(c.restriction, f), c.playable = h(c.availability, f);
c.restriction != void 0 && delete c.restriction;
if (c.related != void 0) {
m = 0;
for (o = c.related.length; m < o; ++m) c.related[m] = b(c.related[m], null)
}
return c
},
c = ["album_group", "single_group", "compilation_group", "appears_on_group"],
a = function(f, l) {
if (f.gid != void 0) f.id = d.str2hex(f.gid), delete f.gid;
if (f.top_track != void 0) {
for (var m = f.top_track, o = [], k = 0, p = m.length; k < p; ++k) {
var q =
m[k];
if (q.country != void 0 && q.country == l.country) {
if (q.track != void 0) o = m[k].track;
break
}
}
k = 0;
for (p = o.length; k < p; ++k) o[k] = i(o[k], null);
f.top_track = o
}
m = 0;
for (o = c.length; m < o; ++m) if (k = c[m], f[k] != void 0) {
for (var p = f[k], q = 0, s = p.length; q < s; ++q) {
var u = p,
w = q,
v = p[q],
t = l,
y = [];
if (v.album != void 0) for (var y = v.album, v = 0, C = y.length; v < C; ++v) y[v] = b(y[v], t);
u[w] = y
}
f[k] = p
}
if (l != null) f.availability = g(f.restriction, l), f.playable = h(f.availability, l);
f.restriction != void 0 && delete f.restriction;
if (f.related != void 0) {
m = 0;
for (o =
f.related.length; m < o; ++m) f.related[m] = a(f.related[m], null)
}
return f
},
g = function(a, b) {
var c = {},
g = !1;
if (typeof a === "undefined" || a.length == 0) return "available";
for (var i = 0, d = a.length; i < d; ++i) {
var h = a[i],
s, u = !0;
h.countries_allowed != void 0 ? (u = h.countries_allowed.length != 0, s = f(b.country, h.countries_allowed)) : s = h.countries_forbidden !== void 0 ? !f(b.country, h.countries_forbidden) : !1;
if (s && h.catalogue != void 0) for (s = 0; s < h.catalogue.length; ++s) {
var w = h.catalogue[s];
if (w.toLowerCase() == "ad" || w.toLowerCase() == "free") c.free = !0;
else if (w.toLowerCase() == "subscription" || w.toLowerCase() == "premium") c.premium = !0
}
if (h.type == void 0 || h.type.toLowerCase() == "streaming") g |= u
}
return g && b.catalogue == "all" ? "available" : c[b.catalogue] ? b.catalogue == "premium" ? "premium" : "available" : c.premium ? "premium" : g ? "regional" : "unavailable"
},
i = function(c, f) {
if (c.gid != void 0) c.id = d.str2hex(c.gid), delete c.gid;
if (c.album != void 0) c.album = b(c.album, null);
if (c.artist != void 0) for (var m = 0, o = c.artist.length; m < o; ++m) c.artist[m] = a(c.artist[m], null);
if (f != null) {
var m =
g(c.restriction, f),
o = h(m, f),
k;
if (k = o) {
a: {
if (c.file != void 0) {
k = 0;
for (var p = c.file.length; k < p; ++k) if (c.file[k].format == "MP3_160") {
k = !0;
break a
}
delete c.file
}
k = !1
}
k = !k
}
k && (m = "unavailable", o = !1);
c.availability = m;
c.playable = o
}
c.restriction != void 0 && delete c.restriction;
if (c.playable) c.playableId = c.id;
else if (c.alternative != void 0) {
m = 0;
for (o = c.alternative.length; m < o; ++m) if (k = i(c.alternative[m], f), k.playable) {
c.availability = k.availability;
c.playable = k.playable;
c.playableId = k.id;
break
}
delete c.alternative
}
return c
};
return {
isPlayable: h,
parseRestrictions: g,
parseTrack: i,
parseAlbum: b,
parseArtist: a
}
}();
Spotify.Parsers.Search = function() {
var d = Spotify.DebuggerJS,
h = function(a) {
return a ? Spotify.Utils.isArray(a) ? a : [a] : []
},
f = function(a, b) {
if (!a.id) return {};
if (a["album-type"]) a.type = a["album-type"].toUpperCase();
if (a["artist-id"] && a["artist-name"]) {
var i = a.artists = [];
if (Spotify.Utils.isArray(a["artist-id"]) && Spotify.Utils.isArray(a["artist-name"])) for (var d = Math.min(a["artist-id"].length, a["artist-name"].length), f = 0; f < d; ++f) i.push({
id: a["artist-id"][f],
name: a["artist-name"][f]
});
else i.push({
id: a["artist-id"],
name: a["artist-name"]
})
}
a.cover = c(a);
if (a.popularity) a.popularity = Math.round(parseFloat(a.popularity) * 100);
if (a.restrictions) a.restrictions = g(a.restrictions.restriction);
a.availability = Spotify.Parsers.Metadata.parseRestrictions(a.restrictions, b);
a.playable = Spotify.Parsers.Metadata.isPlayable(a.availability, b);
delete a.restrictions;
delete a["album-type"];
delete a["artist-id"];
delete a["artist-name"];
delete a["external-ids"];
delete a["cover-small"];
delete a["cover-large"];
return a
},
b = function(a, b) {
if (!a.id) return {};
if (a.portrait) {
var c = a.portrait,
i = [];
c.id && i.push({
size: "DEFAULT",
file_id: c.id,
width: parseInt(c.width),
height: parseInt(c.height)
});
c.small && i.push({
size: "SMALL",
file_id: c.small
});
c.large && i.push({
size: "LARGE",
file_id: c.large
});
a.portrait = i
}
if (a.popularity) a.popularity = Math.round(parseFloat(a.popularity) * 100);
if (a.restrictions) a.restrictions = g(a.restrictions.restriction);
a.availability = Spotify.Parsers.Metadata.parseRestrictions(a.restrictions, b);
a.playable = Spotify.Parsers.Metadata.isPlayable(a.availability, b);
delete a.restrictions;
return a
},
c = function(a) {
var b = [];
a.cover && (b.push({
size: "DEFAULT",
file_id: a.cover
}), delete a.cover);
a["cover-small"] && (b.push({
size: "SMALL",
file_id: a["cover-small"]
}), delete a["cover-small"]);
a["cover-large"] && (b.push({
size: "LARGE",
file_id: a["cover-large"]
}), delete a["cover-large"]);
return b
},
a = function(a) {
return !a.uri ? {} : a
},
g = function(a) {
for (var a = h(a), b = 0, c = a.length; b < c; ++b) {
var g = a[b]["@attributes"],
i = {};
if (g.allowed !== void 0) i.countries_allowed = g.allowed.replace(/,/g, "");
if (g.forbidden !== void 0) i.countries_forbidden = g.forbidden.replace(/,/g, "");
if (g.catalogues !== void 0) i.catalogue = g.catalogues.split(",");
a[b] = i
}
return a
},
i = function(a, b) {
if (!a.id) return {};
if (a.album && a["album-id"]) a.album = {
name: a.album,
id: a["album-id"],
artist: {
name: a["album-artist"],
id: a["album-artist-id"]
},
cover: c(a)
};
if (a["album-artist"] && a["album-artist-id"]) {
a.album = a.album || {};
var d = a.album.artists = [];
if (Spotify.Utils.isArray(a["album-artist"]) && Spotify.Utils.isArray(a["album-artist-id"])) for (var f =
Math.min(a["album-artist"].length, a["album-artist-id"].length), n = 0; n < f; ++n) d.push({
id: a["album-artist-id"][n],
name: a["album-artist"][n]
});
else d.push({
id: a["album-artist-id"],
name: a["album-artist"]
})
}
if (a.artist && a["artist-id"]) if (d = a.artists = [], Spotify.Utils.isArray(a.artist) && Spotify.Utils.isArray(a["artist-id"])) {
f = Math.min(a.artist.length, a["artist-id"].length);
for (n = 0; n < f; ++n) d.push({
id: a["artist-id"][n],
name: a.artist[n]
})
} else d.push({
id: a["artist-id"],
name: a.artist
});
if (a.length) a.length = parseInt(a.length);
if (a.popularity) a.popularity = Math.round(parseFloat(a.popularity) * 100);
if (a.number) a.number = parseInt(a["track-number"]);
if (a.year) a.year = parseInt(a.year);
if (a.title) a.name = a.title;
if (a.restrictions) a.restrictions = g(a.restrictions.restriction);
a.availability = Spotify.Parsers.Metadata.parseRestrictions(a.restrictions, b);
a.playable = Spotify.Parsers.Metadata.isPlayable(a.availability, b);
if (a.playable) a.playableId = a.id;
else if (a.alternatives) {
d = h(a.alternatives.track);
n = 0;
for (f = d.length; n < f; ++n) {
var q = i(d[n], b);
if (q.playable) {
a.availability = q.availability;
a.playable = q.playable;
a.playableId = q.id;
break
}
}
}
delete a.alternatives;
delete a.restrictions;
delete a["album-id"];
delete a["album-artist"];
delete a["album-artist-id"];
delete a.artist;
delete a.cover;
delete a["cover-small"];
delete a["cover-large"];
delete a["artist-id"];
delete a["external-ids"];
delete a.files;
delete a["track-number"];
delete a.title;
return a
},
n = function(a, b, c) {
for (var a = h(a), g = 0, i = a.length; g < i; ++g) a[g] = c(a[g], b);
return a
};
return {
parse: function(c, g) {
var h = (new Date).getTime(),
k = Spotify.Utils.convertStringToXML(c),
k = Spotify.Utils.convertXMLToJSON(k.documentElement);
if (k.albums) k.albums = n(k.albums.album, g, f);
if (k.artists) k.artists = n(k.artists.artist, g, b);
if (k.tracks) k.tracks = n(k.tracks.track, g, i);
if (k.playlists) k.playlists = n(k.playlists.playlist, g, a);
if (k["did-you-mean"]) k.didYouMean = k["did-you-mean"], delete k["did-you-mean"];
k.total = {
albums: parseInt(k["total-albums"]),
artists: parseInt(k["total-artists"]),
tracks: parseInt(k["total-tracks"]),
playlists: parseInt(k["total-playlists"])
};
delete k["total-albums"];
delete k["total-artists"];
delete k["total-tracks"];
delete k["total-playlists"];
delete k.version;
d.log("Spotify.Parsers.Search", ["It took", (new Date).getTime() - h, "ms to parse the search result"], "parsing_times");
return k
}
}
}();
Spotify.Parsers.Suggest = function() {
var d = Spotify.Link,
h = Spotify.Utils,
f = function(b) {
for (var c = 0, a = b.length; c < a; ++c) {
var g = b[c];
if (g.gid) g.id = h.str2hex(g.gid), delete g.gid;
if (g.image) g.image = h.str2hex(g.image);
if (g.image_uri) {
var i = d.fromString(g.image_uri);
g.image = i.id || i.ids[0];
delete g.image_uri
}
i = g.artists = [];
if (Spotify.Utils.isArray(g.artist_gid) && Spotify.Utils.isArray(g.artist_name)) for (var f = Math.min(g.artist_name.length, g.artist_gid.length), l = 0; l < f; ++l) i.push({
id: h.str2hex(g.artist_gid[l]),
name: g.artist_name[l]
});
delete g.artist_gid;
delete g.artist_name;
if (g.owner_uri && g.owner_name) g.user = {
uri: g.owner_uri,
name: g.owner_name
};
delete g.owner_name;
delete g.owner_uri;
if (g.rank) g.popularity = Math.round(g.rank * 100 / 2147483647), delete g.rank
}
return b
};
return {
parse: function(b) {
return {
artists: f(b.artist || []),
albums: f(b.album || []),
tracks: f(b.track || []),
playlist: f(b.playlist || [])
}
}
}
}();
Spotify.Parsers.Playlist = function() {
var d = function(d) {
var f = [];
if (typeof d !== "undefined" && typeof d.items !== "undefined") for (var b = 0; b < d.items.length; b++) {
var c;
a: {
var a = d.items[b],
g = null;
if (typeof a !== "undefined" && typeof a.uri !== "undefined") try {
g = Spotify.Link.fromString(a.uri);
if (g.type === "collectiontracklist") {
c = null;
break a
}
if (g.username && encodeURIComponent(encodeURIComponent(g.username)) == g.username) g.username = decodeURIComponent(g.username)
} catch (i) {
g = Spotify.Link.emptyLink()
}
c = g || Spotify.Link.emptyLink()
}
c !== null && f.push(c)
}
return f
};
this.parsePlaylist = function(h) {
if (typeof h.contents !== "undefined") h.contents = d(h.contents);
if (typeof h.revision !== "undefined") h.revision = Spotify.Utils.str2hex(h.revision);
return h
};
this.parsePublishedPlaylist = function(h) {
if (typeof h.contents !== "undefined") h.contents = d(h.contents), h.length = h.contents.length;
if (typeof h.revision !== "undefined") h.revision = Spotify.Utils.str2hex(h.revision);
return h
};
this.parseMetadata = function(d) {
return d.attributes
}
};
Spotify.Parsers.AdChooser = {
parseServerResponse: function(d) {
d = Spotify.Utils.convertStringToXML(d);
return Spotify.Utils.convertXMLToJSON(d.documentElement)
},
parseAudioAdsVersion1: function(d) {
var h = {
"audio-ad-break": {},
AdQueueEntry: []
},
f = {};
try {
if (typeof d.rules.rule !== "undefined") for (var b = 0, c = d.rules.rule.length; b < c; b += 1) {
var a = d.rules.rule[b];
f[a.id] = a
}
h["audio-ad-break"] = d["audio-ad-break"];
if (typeof d.ads["audio-ad"] !== "undefined") {
var g = [];
d.ads["audio-ad"].length > 0 ? g = d.ads["audio-ad"] : typeof d.ads["audio-ad"].ad_version !== "undefined" && g.push(d.ads["audio-ad"]);
b = 0;
for (c = g.length; b < c; b += 1) {
for (var i = g[b], d = [], n = 0, l = i.rules.id.length; n < l; n += 1) a = i.rules.id[n], d.push(f[a]);
for (var n = null, m = 0, o = i.files.file.length; m < o; m += 1) {
var k = i.files.file[m];
if (k["@attributes"].format === "MPEG 1 layer 3,160000,0,1,1") {
n = k["@attributes"].id;
break
}
}
var p = {
has_been_played: !1,
has_been_clicked: !1,
adPlayCount: 0,
campaignPlayCount: 0,
ids_valid: !0,
non_explicit: i["non-explicit-only"] || 0,
is_test_ad: !1,
priority: parseFloat(i.priority),
duration: parseInt(i.duration, 10),
min_duration: 0,
ad_version: i.ad_version || 1,
start_time_earliest: parseInt(i.starttime),
start_time_latest: parseInt(i.endtime),
campaign_expiry: parseInt(i.expiry),
adclass: 0,
adchooserkind: null,
adkind: "ENC_AD_AUDIO",
rules: d,
ad_id: i.id,
campaign_id: i.campaign,
advertiser: i.advertiser,
target_url: i.url,
token: i.token,
tracking_url: typeof i["tracking-url"] === "string" ? i["tracking-url"] : null,
files: i.files,
image_id: i.image,
embed: null,
banner_size: null,
banner_type: null,
html: null,
title: i.title,
caption: i.caption,
file_id: n,
large_bgcolor: null,
large_image_id: null,
fullscreen_delay: null,
fullscreen_inactivity_timeout: null,
background_target_url: null,
message: null,
level: null
};
h.AdQueueEntry.push(p)
}
}
} catch (q) {}
return h
}
};
Spotify.Services.Suggest = function(d) {
Spotify.EventTarget.call(this);
var h = this,
f, b, c = !1,
a = null,
g = new Spotify.Events,
i = function() {
(c = !0) && a != null && h.trigger(g.READY)
},
n = function(b) {
a = b.response;
c && a != null && h.trigger(g.READY)
},
l = function() {
a = null
};
this.onReady = function(b, i) {
c && a != null ? b.call(i) : h.bind(g.READY, b, i)
};
this.suggest = function(g, i, d) {
c && a != null ? (g = encodeURIComponent(g), (new Spotify.Hermes.ProtobufRequest({
uri: "hm://searchsuggest/suggest/" + g + "?country=" + a.country + "&catalogues=" + a.catalogue,
method: "GET"
}, [], [], [b.msg("Suggestions")])).send(f, function(a, b) {
if (b == 200) {
var c = Spotify.Parsers.Suggest.parse(a[0]);
i(c, b)
} else d(new Spotify.Errors.Error([13, b, ""]))
}, d, !1, !1, "searchsuggest")) : d(new Spotify.Errors.Error([13, 503, "Suggest service not ready!"]))
};
this.init = function(a, c) {
f = a;
c.onReady(function() {
c.getUserInfo(n, l)
}, this);
try {
b = new Spotify.Protobuf.Schema([], null, null, null), b.id = "suggest", b.type = "proto", b.setData(d), b.encode(), i.call(this, i)
} catch (g) {
throw g;
}
}
};
Spotify.Services.AppStore = function(d) {
Spotify.EventTarget.call(this);
var h = new Spotify.Events,
f, b, c = function() {
this.serviceIsReady = !0;
this.trigger(h.READY)
};
this.serviceIsReady = !1;
this.onReady = function(a, b) {
this.serviceIsReady ? a.call(b) : this.bind(h.READY, a, b)
};
this.list = function(a, c, i) {
if (this.serviceIsReady) {
var d = [b.msg("RequestHeader")],
h = [b.msg("AppList")];
(new Spotify.Hermes.ProtobufRequest({
uri: "hm://appstore/app/list",
method: "GET"
}, a, d, h)).send(f, c, i, !1, !1, "appstore")
} else i(new Spotify.Errors.Error([13, 503, "Appstore service not ready!"]))
};
this.init = function(a) {
f = a;
try {
b = new Spotify.Protobuf.Schema([], null, null, null), b.id = "appstore", b.type = "proto", b.setData(d), b.encode(), c.call(this, c)
} catch (g) {
throw g;
}
}
};
Spotify.Services.PopCount = function(d) {
var h = new Spotify.Events,
f, b, c = function() {
this.serviceIsReady = !0;
this.trigger(h.READY)
};
this.serviceIsReady = !1;
this.onReady = function(a, b) {
this.serviceIsReady ? a.call(b) : this.bind(h.READY, a, b)
};
this.get = function(a, c, i, d, h, m) {
this.serviceIsReady ? (a = {
uri: "hm://popcount/" + Spotify.Link.fromString(a).toURLPath() + "?maxUsers=" + (typeof c === "number" ? c : 100) + (typeof i === "boolean" ? "&friendsFirst=" + i : "") + (typeof d === "string" ? "&afterUser=" + d : ""),
method: "GET"
}, c = [b.msg("PopcountResult")], (new Spotify.Hermes.ProtobufRequest(a, [], [], c)).send(f, h, m, !1, !1, "PopCount")) : m(new Spotify.Errors.Error([13, 503, "PopCount service not ready!"]))
};
this.init = function(a) {
Spotify.EventTarget.call(this);
f = a;
try {
b = new Spotify.Protobuf.Schema([], null, null, null), b.id = "popcount", b.type = "proto", b.setData(d), b.encode(), c.call(this, c)
} catch (g) {
throw g;
}
}
};
(function() {
var d = Spotify.Link,
h = Spotify.Parsers.Metadata;
Spotify.Services.Metadata = function(f) {
var b, c, a = null,
g = !1,
i = null,
n = new Spotify.Events,
l = function() {
(g = !0) && i != null && b.trigger(n.READY)
},
m = function(a) {
i = a.response;
g && i != null && b.trigger(n.READY)
},
o = function() {
i = null
},
k = function(a) {
switch (a.type) {
case d.Type.TRACK:
return "hm://metadata/track/" + a.id;
case d.Type.ALBUM:
return "hm://metadata/album/" + a.id;
case d.Type.ARTIST:
return "hm://metadata/artist/" + a.id;
default:
throw Error("Unsupported link type!");
}
},
p = function(a) {
switch (a) {
case d.Type.TRACK:
return "hm://metadata/tracks";
case d.Type.ALBUM:
return "hm://metadata/albums";
case d.Type.ARTIST:
return "hm://metadata/artists";
default:
throw Error("Unsupported link type!");
}
},
q = function(b) {
switch (b) {
case d.Type.TRACK:
return a.msg("Track");
case d.Type.ALBUM:
return a.msg("Album");
case d.Type.ARTIST:
return a.msg("Artist");
default:
throw Error("Unsupported link type!");
}
},
s = function(a, b, g) {
var f = function(c, f) {
if (Spotify.Hermes.Request.isSuccess(f)) {
var k = c[0];
switch (a.type) {
case d.Type.TRACK:
k = h.parseTrack(k, i);
break;
case d.Type.ALBUM:
k = h.parseAlbum(k, i);
break;
case d.Type.ARTIST:
k = h.parseArtist(k, i);
break;
default:
throw Error("Unsupported link type!");
}
b(k, f)
} else g(f)
};
this.send = function() {
(new Spotify.Hermes.ProtobufRequest({
uri: k(a),
method: "GET"
}, [], [], [q(a.type)])).send(c, f, g, !1, !1, "metadata")
}
},
u = function(b, g, f) {
var l = b[0].type,
n = function(a, b) {
if (Spotify.Hermes.Request.isSuccess(b)) {
var c = a[0],
k = q(l),
n;
a: switch (l) {
case d.Type.TRACK:
n = h.parseTrack;
break a;
case d.Type.ALBUM:
n = h.parseAlbum;
break a;
case d.Type.ARTIST:
n = h.parseArtist;
break a;
default:
throw Error("Unsupported link type!");
}
if (c.reply == void 0) f(400);
else {
for (var c = c.reply, o = 0, m = c.length; o < m; ++o) {
var p = c[o];
p && Spotify.Hermes.Request.isSuccess(p.status_code) ? (p = k.parseFromStringSync(p.body), p = n(p, i)) : p = null;
c[o] = p
}
g(c, b)
}
} else f(b)
};
this.send = function() {
for (var g = [], i = 0, d = b.length; i < d; ++i) g.push({
uri: k(b[i])
});
(new Spotify.Hermes.ProtobufRequest({
uri: p(l),
method: "GET",
content_type: "vnd.spotify/mercury-mget-request"
}, [{
request: g
}], [a.msg("MercuryMultiGetRequest")], [a.msg("MercuryMultiGetReply")])).send(c, n, f, !1, !1, "metadata")
}
},
w = function(a) {
if (a instanceof Spotify.Link) return a;
else if (typeof a === "string" || a instanceof String) return d.fromString(a);
else
throw Error("Invalid argument!");
};
return {
onReady: function(a, c) {
g && i != null ? a.call(c) : b.bind(n.READY, a, c)
},
lookup: function(a, b, c) {
if (g && i != null) if (Spotify.Utils.isArray(a)) if (a.length > 1) {
for (var d = Math.ceil(a.length / 100), f = !1, h = [], k = [], l = function(a) {
f || (Array.prototype.push.apply(k, a), --d == 0 && b(k, 200))
}, n = function(a) {
f = !0;
c(a)
}, o = 0, m = a.length; o < m; ++o) h.push(w(a[o]));
do(new u(h.splice(0, 100), l, n)).send();
while (h.length > 0)
} else a.length == 1 ? (new s(w(a[0]), function(a, c) {
b([a], c)
}, c)).send() : c(Error("Array does not contain any items!"));
else(new s(w(a), b, c)).send();
else c(Error("Service not ready!"))
},
init: function(g, i) {
Spotify.EventTarget.call(this);
b = this;
c = g;
i.onReady(function() {
i.getUserInfo(m, o)
}, this);
try {
a = new Spotify.Protobuf.Schema([], null, null, null), a.id = "metadata", a.type = "proto", a.setData(f), a.encode(), l.call(this, l)
} catch (d) {
throw d;
}
}
}
}
})();
Spotify.Services.Search = function() {
var d, h, f = null,
b = new Spotify.Events,
c = function(a) {
f = a.response;
f != null && d.trigger(b.READY)
},
a = function() {
f = null
};
this.DEFAULT_TOTAL_RESULTS = 50;
this.TRACKS = 1;
this.ALBUMS = 2;
this.ARTISTS = 4;
this.PLAYLISTS = 8;
this.ALL = this.TRACKS | this.ALBUMS | this.ARTISTS | this.PLAYLISTS;
this.onReady = function(a, c) {
f != null ? a.call(c) : d.bind(b.READY, a, c)
};
this.search = function(a, b, c, d) {
if (f != null) if (typeof a === "undefined" || a === "") d(new Spotify.Errors.Error([403, 0, "You haven't provided a valid query"]));
else {
b = b || {};
b.type = b.type || this.ALL;
b.total = b.total || this.DEFAULT_TOTAL_RESULTS;
b.offset = b.offset || 0;
if (b.total > this.DEFAULT_TOTAL_RESULTS) b.total = this.DEFAULT_TOTAL_RESULTS;
h.rpc("search", [a, b.type, b.total, b.offset], function(a) {
a = Spotify.Parsers.Search.parse(a.response, f);
c(a)
}, d, this, !1, 2, "search")
} else d(new Spotify.Errors.Error([503, 0, "Search service not ready!"]))
};
this.init = function(b, i) {
Spotify.EventTarget.call(this);
d = this;
h = b;
i.onReady(function() {
i.getUserInfo(c, a)
}, this)
}
};
Spotify.Services.Toplist = function(d) {
Spotify.EventTarget.call(this);
var h = this,
f, b, c = !1,
a = null,
g = new Spotify.Cache.Default,
i = !1,
n = new Spotify.Events,
l = !1,
m = !1,
o = !1,
k = function() {
return c && i && a != null
},
p = function() {
l && m && o && h.trigger(n.READY)
},
q = function() {
h.lookupForUser(a.user, h.PLAYLIST, function() {
o = !0;
p()
}, function() {
o = !0;
p()
});
h.lookupForUser(a.user, h.TRACK, function(a) {
var b = !1;
Spotify.Utils.isArray(a) ? a.length === 0 && (b = !0) : b = !0;
b ? s() : (l = !0, p())
}, function() {
s()
});
h.lookupForUser(a.user, h.ARTIST, function(a) {
var b = !1;
Spotify.Utils.isArray(a) ? a.length === 0 && (b = !0) : b = !0;
b ? u() : (m = !0, p())
}, function() {
u()
})
},
s = function() {
h.lookupForRegion(h.GLOBAL, h.TRACK, function() {
l = !0;
p()
}, function() {
l = !0;
p()
})
},
u = function() {
h.lookupForRegion(h.GLOBAL, h.ARTIST, function() {
m = !0;
p()
}, function() {
m = !0;
p()
})
},
w = function() {
c = !0;
k() && q()
},
v = function(b) {
a = b.response;
k() && q()
},
t = function() {
a = null
},
y = function() {
i = !0;
k() && q()
},
C = function() {
i = !1
},
x = {
track: Spotify.Link.trackLink,
album: Spotify.Link.albumLink,
artist: Spotify.Link.artistLink,
playlist: Spotify.Link.playlistLink
},
z = function(c, d, i, h, k, l, n) {
var n = n || a.user,
o = function(a) {
if (a[0].items != void 0) {
for (var a = a[0].items, b = 0, d = a.length; b < d; ++b) a[b] = x[i](a[b]);
g.put(c, a);
h(a, i, 200)
} else if (a[0].uris != void 0) {
a = a[0].uris;
b = 0;
for (d = a.length; b < d; ++b) a[b] = Spotify.Link.fromString(a[b]);
g.put(c, a);
h(a, i, 200)
} else g.put(c, []), k(new Spotify.Errors.Error([13, 404, "No results"]))
},
m = function(a, c) {
if (c != null) c.length === 0 ? k(new Spotify.Errors.Error([13, 404, "No results"])) : h(c, i, 200);
else {
var g = [],
l = [],
m = {};
i === "playlist" ? (g = [b.msg("TopPlaylistsRequest")], l = [b.msg("TopPlaylistsReply")], m = {
username: n,
uri: d,
method: "GET"
}) : (l = [b.msg("Toplist")], m = {
uri: d,
method: "GET"
});
(new Spotify.Hermes.ProtobufRequest(m, [], g, l)).send(f, o, k, !1, !1, "toplist")
}
};
l ? m(c, null) : g.get(c, m)
};
this.TRACK = "track";
this.ALBUM = "album";
this.ARTIST = "artist";
this.PLAYLIST = "playlist";
this.GLOBAL = "global";
this.onReady = function(b, g) {
c && i && a != null && l && m && o ? b.call(g) : h.bind(n.READY, b, g)
};
this.lookupForUser = function(b, c, g, d, i) {
if (k()) {
var b =
b || a.user,
f = Spotify.Link.userToplistLink(b, c).toURI(),
h = "hm://toplist/toplist/user/" + b + "?type=" + c;
c === "playlist" && (h = "hm://socialgraph/suggestions/topplaylists");
z(f, h, c, g, d, i, b)
} else d(new Spotify.Errors.Error([13, 503, "Toplist service not ready!"]))
};
this.lookupForRegion = function(b, c, g, d, i) {
if (k) {
var b = b || a.country,
f = b == "global",
h = Spotify.Link.toplistLink(c, f ? null : b, f).toURI();
z(h, f ? "hm://toplist/toplist/region?type=" + c : "hm://toplist/toplist/region/" + b + "?type=" + c, c, g, d, i)
} else d(new Spotify.Errors.Error([13, 503, "Toplist service not ready!"]))
};
this.init = function(a, c) {
f = a;
c.onReady(function() {
c.getUserInfo(v, t)
}, this);
g.initialize(y, C, this);
try {
b = new Spotify.Protobuf.Schema([], null, null, null), b.id = "toplist", b.type = "proto", b.setData(d), b.encode(), w.call(this, w)
} catch (i) {
throw i;
}
}
};
Spotify.Services.Playlist = function(d) {
Spotify.EventTarget.call(this);
this.DEFAULT_TOTAL_RESULTS = 200;
var h = Spotify.Utils.isArray,
f = {},
b = this,
c, a = null,
g = !1,
i, n = new Spotify.Events,
l = new Spotify.Parsers.Playlist,
m = [],
o = null,
k = function() {
g = !0;
s() && b.trigger(n.READY)
},
p = function(c) {
a = c.response;
s() && b.trigger(n.READY)
},
q = function() {
a = null
},
s = function() {
return g && a != null
},
u = function(a, b) {
b = typeof b !== "undefined" && b.length ? "?" + b.join("&") : "";
return "hm://playlist/" + a.split(":").join("/").substr(8) + b
},
w = function(a) {
return function() {
for (var b =
0; b < a.length; b++) typeof a[b] === "function" && a[b].apply(this, arguments)
}
},
v = function(a, b, c, g, d) {
for (var c = c.slice(0), i = 0; i < b.contents.length; i++) {
var f = b.contents[i];
if (f.type != "empty") for (var h = 0; h < c.length; h++) f.toURI() == c[h] && delete c[h]
}
b = [];
for (i = 0; i < c.length; i++) c[i] && b.push(c[i]);
b.length > 0 ? t("ADD", a, null, b.join(","), g, d)() : typeof g === "function" && g(!0)
},
t = function(a, b, g, d, h, k) {
var l = [];
a === "ADD" && l.push("add_first");
a = "APPEND" === a ? "ADD" : a;
l.push("syncpublished=1");
var n = [],
n = a === "REMOVE" || a === "ADD" || a === "APPEND" ? [] : [i.msg("OpList")];
if (g && a === "CHANGE") {
var o = parseInt(g.revision.substr(0, 8), 16),
g = g.revision.substr(8);
l.push("revision=" + (o + "," + g))
}
var m = {
uri: u(b, l),
method: a
},
p = 0,
q = 0,
t = function() {
(new Spotify.Hermes.ProtobufRequest(m, [d], n, [])).send(c, function() {
typeof h === "function" && (f[b] = !0, h(!0))
}, s, !0, !1, "playlist")
},
s = function() {
q >= 4 ? typeof k === "function" && k.apply(this, arguments) : (p = Math.floor(2 * q * Math.random()) * 500, q++, setTimeout(t, p))
};
return t
};
this.onReady = function(a, b) {
s() ? a.call(b) : this.bind(n.READY, a, b)
};
this.metadata = function(a, b, g) {
if (s()) {
typeof a == "string" && (a = Spotify.Link.fromString(a));
if (decodeURIComponent(decodeURIComponent(a.username)) == a.username) a.username = encodeURIComponent(a.username);
var d = {
uri: u(a.toURI()),
method: "HEAD"
},
h = [i.msg("SelectedListContent")],
k = typeof f[a.toURI() + ":rename"] === "undefined" ? !1 : f[a.toURI() + ":rename"];
(new Spotify.Hermes.ProtobufRequest(d, [], [], h)).send(c, function(c) {
f[a.toURI() + ":rename"] = !1;
var i = a.toURI();
if (typeof c == "undefined" || typeof c[0] == "undefined") g(new Spotify.Errors.Error([13, 404, "No results"]));
else {
c = l.parseMetadata(c[0]);
c.owner = Spotify.Link.fromString(i).username;
if (encodeURIComponent(encodeURIComponent(c.owner)) == c.owner) c.owner = decodeURIComponent(c.owner);
b(c)
}
}, g, !1, k, "playlist")
} else g(new Spotify.Errors.Error([13, 503, "Playlist service not ready!"]))
};
this.subscribe = function(a, b, c) {
clearTimeout(o);
if (s()) {
for (var g = h(a.uri) ? a.uri : [a.uri], i = g.length; i--;) {
var d = Spotify.Link.fromString(g[i]);
if (decodeURIComponent(decodeURIComponent(d.username)) == d.username) d.username = encodeURIComponent(d.username);
g[i] = d.toURI()
}
if (decodeURIComponent(decodeURIComponent(a.username)) == a.username) a.username = encodeURIComponent(a.username);
m.push({
username: a.username,
uri: g,
callback: b,
errback: c
});
var f = this,
k;
o = setTimeout(function() {
k = m.slice(0);
o = null;
m = [];
for (var b = {}, c = {}, g = {}, i = {}, d = 0; d < k.length; d++) i = k[d], b[i.username] = b[i.username] || [], c[i.username] = c[i.username] || [], g[i.username] = g[i.username] || [], b[i.username] = b[i.username].concat(i.uri), c[i.username].push(i.callback), g[i.username].push(i.errback);
for (var h in b) {
var l = b[i.username],
n = w(c[i.username]),
p = w(g[i.username]),
q = Spotify.Link.rootlistLink(a.username).toURI();
f.list({
uri: q,
total: -1
}, function(a) {
v(q, a, l, n, p)
}, p);
a.publish && setTimeout(function() {
var b = Spotify.Link.publishedRootlistLink(a.username).toURI();
f.list({
uri: b,
total: -1
}, function(a) {
v(b, a, l)
}, function() {})
}, 0)
}
}, 100)
} else c(new Spotify.Errors.Error([13, 503, "Playlist service not ready!"]))
};
this.list = function(a, b, g) {
if (s()) {
typeof a.total === "undefined" ? a.total = this.DEFAULT_TOTAL_RESULTS : a.total > this.DEFAULT_TOTAL_RESULTS ? a.total = this.DEFAULT_TOTAL_RESULTS : a.total == -1 && delete a.total;
if (typeof a.offset === "undefined") a.offset = 0;
var d = Spotify.Link.fromString(a.uri);
if (decodeURIComponent(decodeURIComponent(d.username)) == d.username) d.username = encodeURIComponent(d.username);
var h = {
uri: u(d.toURI()),
method: "GET"
},
k = typeof a.offset !== "undefined" && typeof a.total !== "undefined";
k && (h.uri += "?from=" + a.offset + "&length=" + a.total);
var a = typeof f[d.toURI()] === "undefined" ? !1 : f[d.toURI()],
n = [i.msg("SelectedListContent")];
(new Spotify.Hermes.ProtobufRequest(h, [], [], n)).send(c, function(a) {
k || (f[d.toURI()] = !1);
typeof a == "undefined" || typeof a[0] == "undefined" ? g(new Spotify.Errors.Error([13, 404, "No results"])) : (a = d.type === "published-rootlist" ? l.parsePublishedPlaylist(a[0]) : l.parsePlaylist(a[0]), d.type == "starred" && a.contents.reverse(), b(a))
}, g, !1, a, "playlist")
} else g(new Spotify.Errors.Error([13, 503, "Playlist service not ready!"]))
};
this.rootlist = function(b, c, g) {
b.username =
a.user;
b.uri = Spotify.Link.rootlistLink(a.user).toURI();
this.list(b, c, g)
};
this.publishedRootlist = function(a, c, g) {
a.offset && delete a.offset;
a.total && delete a.total;
a.uri = Spotify.Link.publishedRootlistLink(a.username).toURI();
this.list(a, function(g) {
b.starredPlaylist({
username: a.username,
total: a.total,
offset: a.offset
}, function() {
g.contents.unshift(Spotify.Link.starredLink(a.username));
g.length += 1;
c(g)
}, function() {
c(g)
})
}, g)
};
this.starredPlaylist = function(a, b, c) {
a.uri = Spotify.Link.starredLink(a.username).toURI();
this.list(a, b, c)
};
this.publishPlaylists = function(b, c, g) {
var i = Spotify.Link.publishedRootlistLink(a.user).toURI();
t("ADD", i, null, b.join(","), c, g)()
};
this.unpublishPlaylists = function(c, g, i) {
var d = Spotify.Link.publishedRootlistLink(a.user).toURI();
b.removeFromPlaylistByUri(d, c, g, i)
};
this.addToPlaylist = function(a, b, c, g) {
t("APPEND", a, null, b.join(","), c, g)()
};
this.addTracksInPlaylist = function(a, c, g, i) {
b.addToPlaylist(a, c, g, i)
};
this.removeFromPlaylistByUri = function(a, b, c, g) {
t("REMOVE", a, null, b.join(","), c, g)()
};
this.removeFromPlaylist = function(a, b, c, g, i) {
this.list({
uri: a,
total: -1
}, function(d) {
t("CHANGE", a, d, {
ops: [{
kind: "REM",
rem: {
fromIndex: b,
length: c
}
}]
}, g, i)()
}, function(a) {
i(a)
})
};
this.starTracks = function(c, g, i) {
var d = Spotify.Link.starredLink(a.user).toURI();
b.addToPlaylist(d, c, g, i)
};
this.unstarTracks = function(c, g, i) {
var d = Spotify.Link.starredLink(a.user).toURI();
b.removeFromPlaylistByUri(d, c, g, i)
};
this.createPlaylist = function(g, d, f) {
var h = {
uri: "hm://playlist/user/" + a.user,
method: "PUT"
},
k = [i.msg("OpList")],
l = [i.msg("CreateListReply")];
(new Spotify.Hermes.ProtobufRequest(h, [{
ops: [{
kind: "UPDATE_LIST_ATTRIBUTES",
update_list_attributes: {
new_attributes: {
values: {
name: g
}
}
}
}]
}], k, l)).send(c, function(c) {
b.subscribe({
username: a.user,
uri: c[0].uri
}, function() {
d(c[0].uri)
}, f)
}, function(a) {
f(a)
}, !0, !1, "playlist")
};
this.renamePlaylist = function(a, b, g, d) {
var h = {
uri: u(a),
method: "CHANGE"
},
k = [i.msg("OpList")];
(new Spotify.Hermes.ProtobufRequest(h, [{
ops: [{
kind: "UPDATE_LIST_ATTRIBUTES",
update_list_attributes: {
new_attributes: {
values: {
name: b
}
}
}
}]
}], k, [])).send(c, function() {
f[a + ":rename"] = !0;
g(!0)
}, d, !0, !1, "playlist")
};
this.synchronize = function(a, b, g, d) {
var a = {
uri: u(a),
method: "CALL"
},
f = [i.msg("Playlist4ServiceCall")],
h = [i.msg("Playlist4ServiceReturn")];
data = [{
kind: "METHOD_SYNCHRONIZE",
synchronizeArgs: {
selection: b
}
}];
(new Spotify.Hermes.ProtobufRequest(a, data, f, h)).send(c, g, d, !1, !1, "playlist")
};
this.init = function(a, b) {
c = a;
b.onReady(function() {
b.getUserInfo(p, q)
}, this);
try {
i = new Spotify.Protobuf.Schema([], null, null, null), i.id = "playlist", i.type = "proto", i.setData(d), i.encode(), k.call(this, k)
} catch (g) {
throw g;
}
}
};
Spotify.Services.User = function() {
var d = this,
h, f = new Spotify.Events,
b = null,
c = !1,
a = [],
g = function() {
this.getUserInfo(i, n, !0)
},
i = function() {},
n = function() {};
this.onReady = function(a, b) {
a.call(b)
};
this.getUserInfo = function(g, i, n) {
typeof n === "undefined" && (n = !1);
b !== null && !n ? g(b) : (a.push({
onSuccess: g,
onError: i
}), c || (c = !0, h.rpc("user_info", [], function(g) {
b = g;
c = !1;
for (var i = 0, h = a.length; i < h; i += 1) a[i].onSuccess(g);
a = [];
d.trigger(f.USER_INFO_CHANGE)
}, function(b) {
c = !1;
for (var g = 0, i = a.length; g < i; g += 1) a[g].onError(b);
a = []
}, this, !1, 2, "userdata")))
};
this.setUserAttribute = function(a, b, c, g) {
h.rpc("set_ua", [a, b], c, g, this, !1, 2, "userdata")
};
this.init = function(a) {
Spotify.EventTarget.call(this);
h = a;
h.bind(f.USER_INFO_CHANGE, g, this)
}
};
Spotify.Services.Social = function(d) {
Spotify.EventTarget.call(this);
var h = Spotify.DebuggerJS,
f = this,
b, c, a = !1,
g = new Spotify.Events,
i = function() {
a = !0;
f.trigger(g.READY)
};
this.onReady = function(b, c) {
a ? b.call(c) : f.bind(g.READY, b, c)
};
this.getUsers = function(a, g, i, d) {
var f = 0,
p = [],
q = 0,
s, u;
typeof g === "undefined" ? g = "fast" : g !== "fast" && g !== "complete" && (g = "fast");
for (f = a.length; q < f; ++q) p.push({
uri: "hm://social/decoration/user/" + a[q]
});
(new Spotify.Hermes.ProtobufRequest({
uri: "hm://social/decorations/" + g,
method: "GET",
content_type: "vnd.spotify/mercury-mget-request"
}, [{
request: p
}], [c.msg("MercuryMultiGetRequest")], [c.msg("MercuryMultiGetReply")])).send(b, function(a, b) {
var g;
u = a[0];
if (typeof u.reply === "undefined") d(400);
else {
u = u.reply;
s = c.msg("DecorationData");
g = (new Date).getTime();
for (var f = 0, k = u.length; f < k; ++f) {
var l = u[f],
l = l.status_code >= 200 && l.status_code < 300 ? s.parseFromStringSync(l.body) : null;
u[f] = l
}
h.log("Spotify.Services.Social", ["It took", (new Date).getTime() - g, "ms to parse the frames"], "parsing_times");
i(u, b)
}
}, d, !1, !1, "social")
};
this.init = function(a) {
b = a;
try {
c = new Spotify.Protobuf.Schema([], null, null, null), c.id = "social", c.type = "proto", c.setData(d), c.encode(), i.call(this, i)
} catch (g) {
throw g;
}
}
};
Spotify.Services.SongUriResolver = function() {
Spotify.EventTarget.call(this);
var d = Spotify.DebuggerJS,
h = new Spotify.Events,
f = this,
b, c = !1,
a, g = !1;
this.IN_CDN = 0;
this.ONLY_ON_STORAGE = 1;
this.RATE_LIMIT_REACHED = 2;
this.TRACK_RESTRICTED = 3;
this.serviceIsReady = !0;
var i = function(a) {
var b = a.params.trackUri,
c = a.params.callback,
a = a.params.errback;
d.log("Spotify.Services.SongUriResolver", ["Rate limit is calling again:", b], "corejs");
f.list(b, c, a)
},
n = function() {
d.log("Spotify.Services.SongUriResolver", ["Rate limit is disabled"], "corejs");
g = !1
};
this.onReady = function(a, b) {
a.call(b)
};
this.list = function(i, h, n) {
var k = Spotify.Link.fromString(i);
if (this.serviceIsReady) {
if (!(k instanceof Spotify.Link)) return d.error("Spotify.Services.SongUriResolver", ["Invalid arguments"], "corejs"), n(Error("Services:SongUriResolver:list Invalid arguments")), !1;
if (g && a.totalPendingRequests() !== 0) {
k = a.getItemAtIndex(0);
if (k !== null && typeof k !== "undefined") {
var p = new Spotify.Errors.Error([Spotify.Errors.Domains.TRACK_ERROR, Spotify.Errors.Codes.TRACK_REQUEST_RATE_LIMITED, ""]);
k.errback(p)
}
a.addToBucket({
trackUri: i,
callback: h,
errback: n
}, !1)
} else {
if (c) return p = new Spotify.Errors.Error([Spotify.Errors.Domains.TRACK_ERROR, Spotify.Errors.Codes.TRACK_REQUEST_RATE_LIMITED, "Skipping song", i]), n(p), !1;
c = !0;
b.rpc("track_uri", ["mp3160", k.id], function(a) {
c = !1;
var b = a.response.type;
if (b === f.IN_CDN) h(a.response, 200), d.log("Spotify.Services.SongUriResolver", ["Song can be loaded", a.response], "corejs");
else {
a = new Spotify.Errors.Error([Spotify.Errors.Domains.TRACK_ERROR, 0, ""]);
a.code =
b;
if (b === f.ONLY_ON_STORAGE) a.description = "Song only on storage";
else if (b === f.RATE_LIMIT_REACHED) a.description = "Rate limit reached";
else if (b === f.TRACK_RESTRICTED) a.description = "Track restricted";
a.data = i;
n(a);
d.error("Spotify.Services.SongUriResolver", ["I could not load the song", a], "corejs")
}
}, function(b) {
c = !1;
b.data = i;
b.domain === Spotify.Errors.Domains.TRACK_ERROR && b.code === Spotify.Errors.Codes.TRACK_REQUEST_RATE_LIMITED ? (d.warn("Spotify.Services.SongUriResolver", ["Rate limit is enabled"], "corejs"), g = !0, a.start(), a.addToBucket({
trackUri: i,
callback: h,
errback: n
}, !1)) : n(b);
d.error("Spotify.Services.SongUriResolver", ["I could not load the song", b], "corejs")
}, this, !0, 2, "track_uri")
}
} else d.error("Spotify.Services.SongUriResolver", ["Service is not ready"], "corejs"), n(Error("Services.SongUriResolver:list Service is not ready"))
};
this.init = function(c) {
b = c;
a = new Spotify.RateLimiter(1E4, 1);
a.bind(h.RATE_LIMIT_CALL, i, this);
a.bind(h.RATE_LIMIT_DISABLED, n, this)
}
};
Spotify.Services.AdChooser = function() {
Spotify.EventTarget.call(this);
var d = Spotify.DebuggerJS,
h = this,
f = !1,
b, c = new Spotify.Events,
a = !1,
g = null,
i = null,
n = 0,
l = null,
m = null,
o = null,
k = [0, 60],
p = 35,
q = 0,
s = 0,
u = 600,
w = 0,
v = [],
t = {},
y = [],
C = null,
x = null,
z = function(a) {
var b = function(a) {
return a
},
c = function(a) {
return a
},
g = "PackageStore";
if (typeof a !== "undefined") typeof a.storageKey !== "undefined" && (g = a.storageKey), typeof a.encrypt === "function" && (b = a.encrypt), typeof a.decrypt === "function" && (c = a.decrypt);
return {
setItem: function(a, i) {
var d = {};
localStorage.getItem(g) && (d = JSON.parse(c(localStorage.getItem(g))));
d[a] = i;
return localStorage.setItem(g, b(JSON.stringify(d)))
},
getItem: function(a) {
var b = {};
localStorage.getItem(g) && (b = JSON.parse(c(localStorage.getItem(g))));
return typeof b[a] === "undefined" ? null : b[a]
},
removeItem: function(a) {
if (localStorage.getItem(g)) {
var i = JSON.parse(c(localStorage.getItem(g)));
delete i[a];
return localStorage.setItem(g, b(JSON.stringify(i)))
}
},
clear: function() {
return localStorage.remove(g)
},
length: function() {
var a = {},
b = 0;
localStorage.getItem(g) && (a = JSON.parse(c(localStorage.getItem(g))));
for (var i in a) a.hasOwnProperty(i) && (b += 1);
return b
}
}
},
B = function(a) {
d.error("Spotify.Services.AdChooser", ["AdChooser Error.. " + ["Domain: " + a.domain, "Code: " + a.code, "Description: " + a.description, "Data: " + a.data].join(",")], "corejs")
},
M = function(a, c) {
if (typeof a === "function" && typeof c === "function") {
var g = y.slice(0);
g.slice(0, 1021);
var i = [0, 1, g.length];
i.push.apply(i, g);
try {
b.rpc("ads", i, a, c, this, !0, 2, "ads")
} catch (d) {
O({
serverError: !0
}), B(new Spotify.Errors.Error([15, 500, "Exception thrown communicating with ad server",
{
extra: d
}]))
}
} else B(new Spotify.Errors.Error([15, 500, "Invalid callbacks specified for _retrieveAudioAdsFromServer",
{
extra: e
}]))
},
H = function(a) {
var b = null;
O();
E(function(a) {
a = a.response;
parseInt(a) > 0 ? w = J() - a : B(new Spotify.Errors.Error([15, 500, "Invalid server time specified",
{
extra: e
}]))
}, function(a) {
B(new Spotify.Errors.Error([15, 500, "Exception thrown retrieving server time",
{
extra: a
}]))
});
b = Spotify.Parsers.AdChooser.parseServerResponse(a.response);
return F(b)
},
E = function(a, c) {
typeof a === "function" && typeof c === "function" ? b.rpc("time", [0], a, c, this, !0, 2, "ads") : B(new Spotify.Errors.Error([15, 403, "Invalid callbacks for retrieveAdServerTime"]))
},
F = function(a) {
var b = parseInt(a["@attributes"].version, 10) | 0,
c = null,
g = null,
i = c = null,
d = null;
if (b === 0) B(new Spotify.Errors.Error([15, 403, "Missing version attribute from audio queue data structure",
{
extra: e
}]));
else if (c = Spotify.Parsers.AdChooser["parseAudioAdsVersion" + b], typeof c === "function") {
c = c(a);
a = parseInt(c["audio-ad-break"].length);
try {
p = a, x.setItem("defaultAdBreakLength", p)
} catch (h) {
B(new Spotify.Errors.Error([15, 500, "Unable to set audio ad break length",
{
extra: h
}]))
}
a = parseInt(c["audio-ad-break"].time_between);
try {
u = a, x.setItem("timeBetweenAdBreak", u)
} catch (k) {
B(new Spotify.Errors.Error([15, 500, "Unable to set audio ad break time between",
{
extra: k
}]))
}
if (typeof(c.AdQueueEntry !== "undefined" && c.AdQueueEntry.length > 0)) {
for (i = 0, d = c.AdQueueEntry.length; i < d; i += 1) g = c.AdQueueEntry[i], v.push(g), typeof t[g.ad_id] === "undefined" && Q(g.ad_id);
D();
x.setItem("audioQueue", JSON.stringify(v));
f = !0
} else O({
serverError: !0
}), B(new Spotify.Errors.Error([15, 204, "No ads received from the ad server"]))
} else B(new Spotify.Errors.Error([15, 500, "No parser exists for audio queue version " + b]))
},
D = function(a) {
try {
typeof a === "undefined" ? v.sort(function(a, b) {
return b.priority - a.priority
}) : v.sort(a)
} catch (b) {
B(new Spotify.Errors.Error([15, 500, "Unable to prioritize ad queue",
{
extra: b
}]))
}
},
G = function(a) {
try {
y.indexOf(a) === -1 && (y.push(a), x.setItem("forbiddenAds", JSON.stringify(y)))
} catch (b) {
B(new Spotify.Errors.Error([15, 500, "Unable to add forbidden ad",
{
extra: b
}]))
}
},
I = function(a) {
try {
q += a, q > p * 2 && (q = p * 2), x.setItem("audioAdBreakAvailableTime", q)
} catch (b) {
B(new Spotify.Errors.Error([15, 500, "Unable to set audio ad break available time",
{
extra: b
}]))
}
},
J = function() {
return Math.round((new Date).getTime() / 1E3)
},
O = function(a) {
var b = !1,
c = J(),
g = Math.floor(Math.random() * k[1] + k[0]);
typeof a !== "undefined" && a.serverError === !0 && (b = !0);
s = b === !1 ? c + 600 + g : c + 3600 + g;
x.setItem("timeOfNextAdServerRequest", s)
},
L = function(a) {
var b = [],
c = t[a.ad_id],
g = J() + w,
i = {
max_campaign_repeats_within: function(b, c) {
var i = g - b,
d = [],
f = a.campaign_id,
h = null;
for (h in t) t.hasOwnProperty(h) && t[h].campaign_id === f && d.concat(t[h].event_history.map(function(a) {
if (a.event === "impression" && a.timestamp >= i) return a
}));
return d.length < c
},
max_repeats_within: function(a, b) {
var i = g - a;
return c.event_history.map(function(a) {
if (a.event === "impression" && a.timestamp >= i) return a
}).length < b
},
max_attempts_within: function(a, b) {
var i = g - a;
return c.event_history.map(function(a) {
if (a.event === "attempt" && a.timestamp >= i) return a
}).length < b
},
max_clicks_within: function(a, b) {
var i = g - a;
return c.event_history.map(function(a) {
if (a.event === "click" && a.timestamp >= i) return a
}).length < b
}
};
if (c.rules.length > 0) for (r in c.rules) if (c.rules.hasOwnProperty(r)) {
var d = c.rules[r];
b.push(i[d.type](parseInt(d.interval), parseInt(d.times)))
}
return b.indexOf(!1) === -1
},
N = function() {
try {
var a = [],
b = null,
c = null,
g = null;
for (c = 0, g = v.length; c < g; c += 1) b = v[c], b.start_time_latest <= J() + w ? (d.log("Spotify.Services.AdChooser", ["Removing expired ad", result], "corejs"), G(b.ad_id)) : L(b) === !1 ? (d.log("Spotify.Services.AdChooser", ["Removing ad with expired rules"], "corejs"), G(b.ad_id)) : a.push(b);
v = a;
x.setItem("audioQueue", JSON.stringify(v));
return v.length - a.length
} catch (i) {
B(new Spotify.Errors.Error([15, 500, "Unable to clear invalid ads in audio ad queue",
{
extra: i
}]))
}
},
K = function(a) {
var b = null,
c = null,
g = null;
for (b = 0, c = v.length; b < c; b += 1) if (g = v[b], g.file_id === a) return g;
return null
},
P = function(a) {
return {
__pid: a.file_id,
name: a.title,
disc: 1,
duration: parseInt(a.duration * 1E3, 10),
number: 1,
popularity: a.tracking_url,
playable: !0,
explicit: !1,
advertisement: !0,
image: a.image_id,
artist: [{
uri: a.target_url,
name: a.advertiser
}]
}
},
Q = function(a, b) {
var c;
a: {
var g = c = null,
i = null;
for (c = 0, g = v.length; c < g; c += 1) if (i = v[c], i.ad_id === a) {
c = i;
break a
}
c = null
}
c !== null ? (typeof t[a] === "undefined" && (t[a] = {
campaign_id: c.campaign_id,
expiry_time: c.campaign_expiry,
rules: c.rules,
event_history: []
}), typeof b !== "undefined" && t[a].event_history.push({
timestamp: J() + w,
event: b
}), x.setItem("adHistory", JSON.stringify(t))) : B(new Spotify.Errors.Error([15, 500, "Unable to locate ad queue entry",
{
extra: b
}]))
},
A = function() {
a === !1 && (g = setInterval(function() {
a = !0;
o.isPlaying === !0 && o.isAd === !1 && n++
}, 1E3), i = setInterval(function() {
x.setItem("streamTimeSinceLastAdBreak", n);
d.log("Spotify.Services.AdChooser", ["Stream time: ", n], "corejs")
}, 1E4))
},
R = function() {
clearInterval(g);
clearInterval(i);
a = !1
};
this.serviceIsReady = !0;
this.onReady = function(a, b) {
f === !0 ? a.call(b) : h.bind(Spotify.Events.READY, a, b)
};
this.setAPI = function(a) {
b = a
};
this.recordAdEvent = function(a, b) {
var c;
c = a.split("spotify:ad:")[1];
c = K(c);
var g = null;
if (c === null) B(new Spotify.Errors.Error([15, 404, "Unable to locate ad to record ad event",
{
extra: a
}]));
else {
b: {
var i = g = null,
d = null;
for (g = 0, i = v.length; g < i; g += 1) if (d = v[g], d.ad_id === c.ad_id) break b;
g = null
}
g === null && B(new Spotify.Errors.Error([15, 404, "Unable to locate ad queue index",
{
extra: c
}]));
switch (b) {
case "click":
v[g].has_been_clicked = !0;
Q(c.ad_id, "click");
break;
case "attempt":
Q(c.ad_id, "attempt");
break;
case "impression":
v[g].has_been_played = !0;
v[g].adPlayCount += 1;
v[g].campaignPlayCount += 1;
Q(c.ad_id, "impression");
break;
default:
B(new Spotify.Errors.Error([15, 500, "Invalid ad event",
{
extra: b
}]))
}
}
};
this.getNextAd = function() {
var a = null,
b = null;
var c = b = a = null,
g = [];
try {
for (a in t) if (t.hasOwnProperty(a)) {
g = [];
for (b = 0, c = t[a].event_history.length; b < c; b += 1) t[a].event_history[b].expiry_time > J() + w && g.push(t[a].event_history[b]);
t[a].event_history = g.slice(0)
}
x.setItem("adHistory", JSON.stringify(t))
} catch (i) {
B(new Spotify.Errors.Error([15, 500, "Unable to purge expired ad history",
{
extra: i
}]))
}
if (n >= u && o.isAd === !1) {
d.log("Spotify.Services.AdChooser", ["Injecting ad!"], "corejs");
I(p);
var a = [],
b = !1,
f = g = c = null;
N();
for (D(); q > 0 && b === !1;) for (c = 0, g = v.length, b = !0; c < g; c += 1) f = v[c], f.duration < q && (a.push(f), I(f.duration * -1), b = !1);
if (a.length > 0) m.setIntercept(C), b = P(a[0]), C.appendWithMeta("spotify:ad:" + a[0].file_id, b), C.setOwner(b.artist[0].uri), m.intercept(), o.ad = a[0]
} else d.log("Spotify.Services.AdChooser", [u - n + " seconds left until ad..."], "corejs")
};
this.lookup = function(a, b) {
var c = [],
g = null,
i = null,
d = null;
if (Spotify.Utils.isArray(a)) {
for (g = 0, i = a.length; g < i; ++g) d = K(a[g].id), c.push(P(d));
b(c, 200)
} else a.length == 1 ? (d = K(a[0].id), c.push(P(d)), b(c, 200)) : B(new Spotify.Errors.Error([15, 404, "Array does not contain any items!"]))
};
this.maybeRetrieveAds = function() {
s <= J() && (d.log("Spotify.Services.AdChooser", ["Retrieving ads from server."], "corejs"), M(H, function() {
O({
serverError: !0
})
}))
};
this.init = function(a, g, i, d, k) {
b = a;
l = g;
m = i;
o = d;
k.onReady(function() {
k.getUserInfo(function(a) {
x =
new z({
storageKey: a.response.user
});
x.getItem("timeBetweenAdBreak") !== null && (u = parseInt(x.getItem("timeBetweenAdBreak"), 10));
x.getItem("defaultAdBreakLength") !== null && (p = parseInt(x.getItem("defaultAdBreakLength"), 10));
x.getItem("timeOfNextAdServerRequest") !== null && (s = parseInt(x.getItem("timeOfNextAdServerRequest"), 10));
x.getItem("streamTimeSinceLastAdBreak") !== null && (n = parseInt(x.getItem("streamTimeSinceLastAdBreak"), 0));
x.getItem("audioQueue") !== null && (v = JSON.parse(x.getItem("audioQueue")));
x.getItem("adHistory") !== null && (t = JSON.parse(x.getItem("adHistory")));
x.getItem("forbiddenAds") !== null && (y = JSON.parse(x.getItem("forbiddenAds")));
N();
h.maybeRetrieveAds();
C = l.create("spotify:ads");
C.setRule("intercept");
m.addEvents({
beforeContextChange: h.getNextAd,
beforeNext: h.getNextAd,
beforePrevious: h.getNextAd,
ended: function() {
o.trackUri.indexOf("spotify:ad:") > -1 && (n = 0)
}
});
o.bind(c.PLAYING, A, h);
o.bind(c.PAUSED, R, h);
f = !0;
h.trigger(c.READY)
}, function(a) {
B(new Spotify.Errors.Error([15, 500, "Exception thrown gathering user info",
{
extra: a
}]))
})
}, this)
}
};
Spotify.Services.AdUriResolver = function() {
Spotify.EventTarget.call(this);
var d = Spotify.DebuggerJS;
this.serviceIsReady = !0;
this.onReady = function(d, f) {
d.call(f)
};
this.list = function(h, f, b) {
var c = this,
a = Spotify.Link.fromString(h);
if (this.serviceIsReady) {
if (!(a instanceof Spotify.Link)) return b(new Spotify.Errors.Error([15, 400, "Invalid arguments"])), !1;
(function(a) {
var i = a.response.type;
if (i === 0) f(a.response, 200);
else {
a = {
method: "ad_uri",
response: a
};
if (i === c.ONLY_ON_STORAGE) a.response = "Song only on storage";
else if (i === c.RATE_LIMIT_REACHED) a.response = "Rate limit reached";
else if (i === c.TRACK_RESTRICTED) a.response = "Track restricted";
a.adUri = h;
d.error("Spotify.Services.AdUriResolver", ["Error with track", a], "corejs");
b(a)
}
})({
method: "ad_uri",
response: {
type: 0,
uri: "http://d7zatysqm84hv.cloudfront.net/mp3-ad/" + a.id
}
})
} else b(new Spotify.Errors.Error([15, 503, "AdUriResolver service not ready!"]))
};
this.init = function() {}
};
Spotify.Services.Pubsub = function(d) {
Spotify.EventTarget.call(this);
var h = this,
f, b, c = new Spotify.Events,
a = {},
g = function(b) {
var c = Spotify.Hermes.Header.parseFromStringSync(Spotify.Utils.Base64.decode(b.params[2]));
if (c) {
var g = a[c.uri],
i;
if (c.status_code === 200) for (var d = 0, f = g.length; d < f; d += 1) i = g[d], i.callback.call(i.context, b.params);
else {
d = 0;
for (f = g.length; d < f; d += 1) i = g[d], i.errorCallback.call(i.context, c)
}
}
},
i = function() {
this.serviceIsReady = !0;
this.trigger(c.READY)
};
this.serviceIsReady = !1;
this.onReady =
function(a, b) {
this.serviceIsReady ? a.call(b) : h.bind(c.READY, a, b)
};
this.subscribe = function(c, g, i, d, h, p, q) {
function s(a) {
h.call(q, a)
}
typeof c === "undefined" || typeof p === "undefined" || typeof d === "undefined" || typeof h === "undefined" || typeof q === "undefined" ? h.call(q, new Spotify.Errors.Error([0, 16, "Not all argments are provided"])) : (Spotify.Utils.isArray(g) || (g = []), Spotify.Utils.isArray(i) || (i = []), this.serviceIsReady ? (new Spotify.Hermes.ProtobufRequest({
uri: c,
method: "SUB"
}, g, i, [])).send(b, function(b) {
var c =
f.msg("Subscription"),
g = [];
if (b) {
for (var i = !1, h = 0; h < b.length; ++h) {
var k = c.parseFromStringSync(b[h]);
if (k.status_code === 200) i = k.uri, g.push(i), typeof a[i] === "undefined" && (a[i] = []), a[i].push({
callback: p,
context: q,
uri: i,
arguments: []
}), i = !0
}
if (!i) {
s();
return
}
}
d.call(q, g)
}, s, !1, !0, "pubsub") : h.call(q, new Spotify.Errors.Error([13, 503, "Suggest service not ready!"])))
};
this.init = function(a) {
b = a;
b.bind(c.HERMES_B64_MESSAGE, g, this);
try {
f = new Spotify.Protobuf.Schema([], null, null, null), f.id = "pubsub", f.type = "proto", f.setData(d), f.encode(), i.call(this, i)
} catch (h) {
throw h;
}
}
};
Spotify.Services.Presence = function(d) {
Spotify.EventTarget.call(this);
var h = this,
f = new Spotify.Events,
b, c = !1,
a = !1,
g = null,
i, n, l = function() {
a = !0;
k()
},
m = function(a) {
g = a.response;
k()
},
o = function() {
g = null
},
k = function() {
if (c && a && g !== null) h.serviceIsReady = !0, h.trigger(f.READY)
},
p = function(a) {
a.length > 0 && (a = n.msg("State").parseFromStringSync(Spotify.Utils.Base64.decode(a[3])), h.trigger(f.NOTIFICATION, a))
},
q = function() {},
s = function(a) {
throw a;
},
u = function(a, b) {
(new Spotify.Hermes.ProtobufRequest({
uri: "hm://presence/user/" + g.user,
method: "SET"
}, [a], [n.msg("State")], [])).send(i, b || q, s, !1, !1, "Presence")
};
this.serviceIsReady = !1;
this.onReady = function(a, b) {
this.serviceIsReady ? a.call(b) : this.bind(f.READY, a, b)
};
this.subscribe = function(a, c, g, i) {
this.serviceIsReady ? typeof a === "undefined" ? g.call(i, new Spotify.Errors.Error([0, 16, "Not all argments are provided"])) : Spotify.Utils.isArray(a) ? b.subscribe("hm://presence/user/", a, [], c, g, p, h) : g.call(i, new Spotify.Errors.Error([0, 16, "Users arguments must be an array"])) : g.call(i, new Spotify.Errors.Error([13, 503, "Presence service not ready!"]))
};
this.broadcastPlaylistPublished = function(a, b) {
var c = {
generic: {
type: 1,
item_uri: a,
timestamp: (new Date).getTime()
}
};
u(c, b)
};
this.broadcastTrackAdded = function(a, b, c) {
a = {
generic: {
type: 2,
context_uri: a,
item_uri: b,
timestamp: (new Date).getTime()
}
};
u(a, c)
};
this.broadcastTrackStartedPlaying = function(a, b, c, g) {
a = {
generic: {
type: 5,
item_uri: a,
context_uri: b,
referrer_uri: c,
timestamp: (new Date).getTime()
}
};
u(a, g)
};
this.broadcastTrackFinishedPlaying = function(a, b, c, g) {
a = {
generic: {
type: 3,
item_uri: a,
context_uri: b,
referrer_uri: c,
timestamp: (new Date).getTime()
}
};
u(a, g)
};
this.broadcastFavoriteAppAdded = function(a, b) {
var c = {
generic: {
type: 4,
item_uri: a,
timestamp: (new Date).getTime()
}
};
u(c, b)
};
this.broadcastUriShared = function(a, b, c) {
a = {
generic: {
type: 6,
item_uri: a,
message: b,
timestamp: (new Date).getTime()
}
};
u(a, c)
};
this.broadcastArtistFollowed = function(a, b, c, g) {
a = {
generic: {
type: 7,
item_uri: a,
item_name: b,
item_image: c,
timestamp: (new Date).getTime()
}
};
u(a, g)
};
this.init = function(a, g, f) {
i = a;
b = g;
b.onReady(function() {
c = !0;
f.onReady(function() {
f.getUserInfo(m, o)
}, this)
});
try {
n = new Spotify.Protobuf.Schema([], null, null, null), n.id = "presence", n.type = "proto", n.setData(d), n.encode(), l.call(h, l)
} catch (k) {
throw k;
}
}
};
Spotify.Services.SocialGraph = function(d) {
var h, f, b = Spotify.DebuggerJS,
c, a, g, i = !1,
n = null,
l = new Spotify.Events,
m = function() {
s("subscriptions", n.user, 1E3, 0, function(a) {
if (a = a[0].users) {
h = h.concat(a);
for (var b = 0, c = a.length; b < c; b++) f[a[b].username] = b;
a.length === 1E3 && m()
}
}, function() {
b.error("Spotify.Services.SocialGraph", ["We failed to cache the user subscirptions", arguments], "corejs")
})
},
o = function(a) {
n = a.response;
i && n !== null && c.trigger(l.READY)
},
k = function() {
n = null
},
p = {
subscribers: {},
subscriptions: {},
dismissed: {},
blocked: {}
};
f = {};
h = [];
var q = function(a, b) {
var c = p[a],
g = "";
if (c[b] && c[b].lastResult) g = c[b].lastResult;
return g
},
s = function(b, c, i, d, f, h, k) {
if (!c) c = n.user;
var l = "hm://socialgraph/" + b + "/user/" + c;
k && (l += "/relevant");
var l = {
uri: l,
method: "GET"
},
o = [],
m = [g.msg("UserListReply")],
i = [{
count: i,
include_length: !0
}];
k ? i = [] : (o = [g.msg("UserListRequest")], i[0].last_result = d === 0 ? "" : q(b, c));
(new Spotify.Hermes.ProtobufRequest(l, i, o, m)).send(a, function(a, g) {
var i = a[0].users;
if (i) {
var d = c,
i = i[i.length - 1].username,
h = p[b];
h[d] = h[d] || {};
h[d].lastResult = i
}
f(a, g)
}, h, !1, !1, "socialgraph")
},
u = function(b, i, d, f, h) {
b = {
uri: "hm://socialgraph/" + b,
method: "POST"
};
if (i) b.method = "DELETE";
var k = [g.msg("StringListRequest")],
n = [g.msg("StringListReply")];
(new Spotify.Hermes.ProtobufRequest(b, [{
args: d
}], k, n)).send(a, function(a, b) {
f(a, b);
c.trigger(i ? l.RELATIONS_UNSUBSCRIBE : l.RELATIONS_SUBSCRIBE, {
users: d
})
}, h, !1, !1, "socialgraph")
},
w = function(b, c, i, d, f) {
var b = {
uri: "hm://socialgraph/" + b + "/user/" + c + "/exists",
method: "GET"
},
c = [g.msg("StringListRequest")],
h = [g.msg("StringListReply")];
(new Spotify.Hermes.ProtobufRequest(b, [{
args: i
}], c, h)).send(a, function(a, b) {
d(a, b)
}, f, !1, !1, "socialgraph")
};
this.onReady = function(a, b) {
i && n !== null ? a.call(b) : c.bind(l.READY, a, b)
};
this.getSubscribers = function(a, b, c, g, i) {
s("subscribers", a, b, c, g, i)
};
this.getRelevantSubscribers = function(a, b, c, g, i) {
s("subscribers", a, b, c, g, i, !0)
};
this.getSubscriptions = function(a, b, c, g, i) {
s("subscriptions", a, b, c, g, i)
};
this.getRelevantSubscriptions = function(a, b, c, g, i) {
s("subscriptions", a, b, c, g, i, !0)
};
this.getDismissed = function(a, b, c, g, i) {
s("dismissed", a, b, c, g, i)
};
this.getBlocked = function(a, b, c, g, i) {
s("blocked", a, b, c, g, i)
};
this.subscribeTo = function(a, b, c) {
u("subscriptions", !1, a, b, c)
};
this.unsubscribeFrom = function(a, b, c) {
u("subscriptions", !0, a, b, c)
};
this.dismiss = function(a, b, c) {
u("dismissed", !1, a, b, c)
};
this.undismiss = function(a, b, c) {
u("dismissed", !0, a, b, c)
};
this.block = function(a, b, c) {
u("blocked", !1, a, b, c)
};
this.unblock = function(a, b, c) {
u("blocked", !0, a, b, c)
};
this.isSubscribed = function(a) {
for (var b = [], c = 0, g = a.length; c < g; c++) b.push(a[c] in f);
return b
};
this.hasSubscribers = function(a, b, c, g) {
w("subscribers", a, b, c, g)
};
this.hasSubscriptions = function(a, b, c, g) {
w("subscriptions", a, b, c, g)
};
this.hasDismissed = function(a, b, c, g) {
w("dismissed", a, b, c, g)
};
this.hasBlocked = function(a, b, c, g) {
w("blocked", a, b, c, g)
};
this.hasHidden = function(a, b, c, g) {
w("hidden", a, b, c, g)
};
this.preloadCurrentUserSubscriptions = m;
this.init = function(b, f) {
Spotify.EventTarget.call(this);
c = this;
a = b;
f.onReady(function() {
f.getUserInfo(o, k)
}, this);
try {
g = new Spotify.Protobuf.Schema([], null, null, null), g.id = "socialgraph", g.type = "proto", g.setData(d), g.encode(), (i = !0) && n !== null && c.trigger(l.READY)
} catch (h) {
throw h;
}
}
};
Spotify.Services.MergedProfile = function(d) {
var h = this,
f = new Spotify.Events,
b, c, a = function() {
this.serviceIsReady = !0;
this.trigger(f.READY)
},
g = function(a, g, d, f) {
h.serviceIsReady ? (a = {
uri: "hm://mergedprofile/mergedprofile/" + a + "/" + g,
method: "GET"
}, g = [c.msg("MergedProfileReply")], (new Spotify.Hermes.ProtobufRequest(a, [], [], g)).send(b, d, f, !1, !1, "mergedprofile")) : f(new Spotify.Errors.Error([13, 503, "MergedProfile service not ready!"]))
};
this.serviceIsReady = !1;
this.onReady = function(a, b) {
this.serviceIsReady ? a.call(b) : this.bind(f.READY, a, b)
};
this.forUser = function(a, b, c) {
g("user", a, b, c)
};
this.forArtist = function(a, b, c) {
g("artist", a, b, c)
};
this.init = function(g) {
Spotify.EventTarget.call(this);
b = g;
try {
c = new Spotify.Protobuf.Schema([], null, null, null), c.id = "mergedprofile", c.type = "proto", c.setData(d), c.encode(), a.call(this, a)
} catch (f) {
throw f;
}
}
};
(function() {
function d(b) {
this._storage = f[b] || (f[b] = {})
}
var h = !1,
f = {};
d.prototype.store = function(b, c) {
store[b] = c;
return this
};
d.prototype.retrieve = function(b) {
return store[b] || null
};
Spotify.getStorage = function(b) {
if (h) throw Error("Cannot fetch from locked storage.");
return new d(b)
};
Spotify.lockStorage = function() {
h = !0;
return this
}
})();
(function() {
function d() {
this._events = {}
}
function h() {
this._keys = [];
this._values = []
}
function f() {
this._ids = [];
this._replies = {}
}
var b = !1,
c = [];
d.prototype.addEvent = function(a, b) {
var c = this._events[a] || (this._events[a] = []);
if (c.indexOf(b) != -1) return this;
c.push(b);
return this
};
d.prototype.addEvents = function(a) {
for (var b in a) a.hasOwnProperty(b) && this.addEvent(b, a[b])
};
d.prototype.removeEvent = function(a, b) {
var c = this._events[a];
if (!c || !c.length) return this;
var d = c.indexOf(b);
if (d == -1) return this;
c.splice(d, 1);
return this
};
d.prototype.fireEvent = function(a, b, c) {
var d = this,
a = this._events[a];
if (!a || !a.length) return this;
for (var a = a.slice(0), f = a.length; f--;)(function(a) {
c ? a.apply(d, b) : setTimeout(function() {
a.apply(d, b)
}, 15)
})(a[f]);
return this
};
Spotify.App = new d;
Spotify.App.EventEmitter = d;
Spotify.App.noop = function() {};
Spotify.App.onReady = function(a, g) {
b && a.call(g || this);
c.push({
fn: a,
bound: g
});
return this
};
Spotify.App.init = function(a, g) {
b = !0;
for (var i = 0, d = c.length; i < d; i++) {
var f = c[i];
f.fn.call(f.bound || this, a, g || {
publisher: {
subscribe: Spotify.App.noop
}
})
}
return this
};
Spotify.App.SourceURLs = {
tiny: "https://d3rt1990lpmkn.cloudfront.net/60/",
normal: "https://d3rt1990lpmkn.cloudfront.net/300/",
small: "https://d3rt1990lpmkn.cloudfront.net/120/",
large: "https://d3rt1990lpmkn.cloudfront.net/640/",
avatar: "https://d3rt1990lpmkn.cloudfront.net/artist_image/"
};
Spotify.App.extractAppName = function(a) {
return (a = a.match(/^https?:\/\/[A-Za-z0-9]{40}-([A-Za-z0-9_-]+).*/)) ? a[1] : null
};
h.prototype.get = function(a) {
a = this._keys.indexOf(a);
return a == -1 ? null : this._values[a]
};
h.prototype.set = function(a, b) {
var c = this._keys,
d = this._values,
f = c.indexOf(a);
if (f != -1) return d[f] = b, this;
c.push(a);
d.push(b);
return this
};
h.prototype.remove = function(a) {
var b = this._keys,
c = this._values,
a = b.indexOf(a);
if (a == -1) return this;
b.splice(a, 1);
c.splice(a, 1)
};
h.prototype.clear = function() {
this._keys.splice(0, this._keys.length);
this._values.splice(0, this._values.length);
return this
};
Spotify.App.WeakMap = h;
f.prototype.push = function(a, b) {
var c = this._ids,
d = this._replies,
a = a.toString();
d[a] || c.push(a);
(d[a] || (d[a] = [])).push(b);
return this
};
f.prototype.takeIds = function(a) {
var b = this._ids,
a = a != void 0 ? a : b.length;
return b.splice(0, a)
};
f.prototype.takeReplies = function(a, b) {
var c = this._replies[a];
if (!c) return [];
var b = b != void 0 ? b : c.length,
d = c.splice(0, b);
c.length || (this._replies[a] = null);
return d
};
Spotify.App.RequestBuffer = f
})();
(function() {
function d() {
this._requests = {};
this._hostMap = {}
}
function h(d, b, c) {
this._id = d;
this._request = b;
this._params = c || [];
this._status = "pending";
this._timestamp = (new Date).getTime();
this._roundtrip = 0
}
Spotify.App.RequestLogger = d;
d.prototype.enter = function(d, b, c, a) {
var g = this._requests,
g = g[d] || (g[d] = {
total: 0,
success: 0,
failure: 0,
pending: 0,
requests: {}
});
g.total++;
g.pending++;
g.requests[b] = new h(b, c, a);
this._hostMap[b] = d
};
d.prototype.succeed = function(d, b) {
var c = this._hostMap[d];
if (!c) return this;
c = this._requests[c];
c.success++;
c.pending--;
c.requests[d].finish(b);
return this
};
d.prototype.fail = function(d, b) {
var c = this._hostMap[d];
if (!c) return this;
c = this._requests[c];
c.failure++;
c.pending--;
c.requests[d].finish(b);
return this
};
d.prototype.get = function(d) {
return this._requests[d] || null
};
d.prototype.formatted = function(d) {
var b = this.get(d);
if (!b) return "No logs for item.";
var c = [];
c.push([d, "- total:", b.total, "- success:", b.success, "- failed:", b.failure, "- pending:", b.pending].join(" "));
var d = b.requests,
a;
for (a in d) c.push(d[a].toString());
return c.join("\n")
};
h.prototype.finish = function(d) {
this._status = d;
this._roundtrip = (new Date).getTime() - this._timestamp;
return this
};
h.prototype.toString = function() {
for (var d = this._params.slice(0, 5), b = Math.max(this._params.length - 5, 0), c = d.length; c--;) d[c] = JSON.stringify(d[c]);
return [" |", [" |- ", this._request, ": ", this._status].join(""), [" | [", this._status == "pending" ? "P" : this._roundtrip + "ms", "] params: [", d.join(", "), b !== 0 ? ", plus " + b + " more.." : "", "]"].join("")].join("\n")
};
h.prototype.toJSON =
h.prototype.toString
})();
(function() {
function d() {
delete Spotify.App.ContextManager;
this.cache = new i(1E3)
}
function h(a, b, c) {
a = new a(b.toString());
this.cache.put(b, a);
return (new g(a)).setExpiry(c)
}
function f(a, c, d, i) {
var f = this.cache.get(c.toString());
if (f) if (f.isExpired()) this.cache.remove(f);
else
return (new g(f)).setExpiry(i);
return d ? a == b ? this.create(c, i) : this.createGroup(c, i) : null
}
function b(a, b) {
this._id = a;
this._rule = n.defaults;
this._currentIndex = 0;
this._shuffled = this._repeated = !1;
this._shuffledList = null;
this._metadata = [];
var c = this._list = this._origin = [];
if (!b) return this;
for (var g = 0, d = b.length; g < d; g++) g in b && b[g] && c.push(b[g])
}
function c(a) {
for (var b = a.length; b;) {
var c = Math.floor(Math.random() * b--),
g = a[b];
a[b] = a[c];
a[c] = g
}
return a
}
function a(a) {
this._id = a;
this._rule = n.defaults;
this._repeated = this._shuffled = !1;
this._currentContext = 0;
this._contexts = [];
this._shuffledContexts = [];
this._noReset = new l;
this._ttl = (new Date).getTime()
}
function g(a) {
this._context = a;
this._owner = ""
}
var i = Spotify.SimpleCache;
Spotify.App.ContextManager =
d;
d.prototype.create = function(a, c) {
return h.call(this, b, a, c)
};
d.prototype.createGroup = function(b, c) {
return h.call(this, a, b, c)
};
d.prototype.get = function(a, c, g) {
return f.call(this, b, a, c, g)
};
d.prototype.getGroup = function(b, c, g) {
return f.call(this, a, b, c, g)
};
d.prototype.remove = function(a) {
return this.cache.remove(a.toString())
};
var n = {
defaults: {
skipCount: -1,
volume: !0,
seek: !0,
indexing: !0,
previous: !0,
next: !0,
shuffle: !0,
repeat: !0
},
intercept: {
skipcount: -1,
volume: !1,
seek: !1,
indexing: !0,
previous: !1,
next: !1,
shuffle: !1,
repeat: !1
},
radio: {
skipCount: -1,
volume: !0,
seek: !0,
indexing: !0,
previous: !1,
next: !0,
shuffle: !1,
repeat: !1
},
dmca: {
skipCount: 6,
volume: !0,
seek: !0,
indexing: !0,
previous: !1,
next: !0,
shuffle: !1,
repeat: !1
},
stream: {
skipcount: -1,
volume: !0,
seek: !1,
indexing: !0,
previous: !1,
next: !1,
shuffle: !1,
repeat: !1
}
};
b.prototype.getId = function() {
return this._anonymous ? null : this._id
};
b.prototype.setAnonymous = function(a) {
this._anonymous = !! a;
return this
};
b.prototype.setRule = function(a) {
return (a = n[a]) ? (this._rule = a, !0) : !1
};
b.prototype.getRule = function() {
return this._rule
};
b.prototype.setRepeat = function(a) {
return !this._rule.repeat ? !1 : this._repeated = a
};
b.prototype.isRepeated = function() {
return this._repeated
};
b.prototype.setShuffle = function(a) {
if (!this._rule.shuffle) return !1;
(this._shuffled = a) ? this._shuffle() : this._unshuffle();
return a
};
b.prototype.isShuffled = function() {
return this._shuffled
};
b.prototype.setExpiry = function(a) {
if (!a || a < 0) return this;
this._time = (new Date).getTime();
this._ttl = a;
return this
};
b.prototype.isExpired =
function() {
var a = this._ttl;
return !a ? !1 : (new Date).getTime() - this._time >= a
};
b.prototype._shufflePartial = function(a) {
var b = this._shuffledList;
if (!b) return this;
for (var g = this._origin.length - a, d = Array(g); g--;) d[g] = a + g;
c(d).unshift(a, 0);
b.splice.apply(b, d);
return this
};
b.prototype._shuffle = function(a) {
if (a != void 0) return this._shufflePartial(a);
for (var b = this._origin.length, a = Array(b); b--;) a[b] = b;
b = a.splice(this._currentIndex, 1).pop();
c(a).unshift(b);
this._list = this._shuffledList = a;
this._currentIndex =
0;
return this
};
b.prototype._unshuffle = function() {
if (!this._shuffledList) return this;
this._list = this._origin;
this._currentIndex = this._shuffledList[this._currentIndex];
return this
};
b.prototype.get = function(a) {
var b = this._origin;
if (a < 0 || a > b.length) return null;
this._shuffled && (a = this._shuffledList[a]);
b = b[a];
a = this._metadata[a];
return !b || !a ? null : {
item: b,
metadata: a
}
};
b.prototype.getList = function() {
return this._origin
};
b.prototype.getLength = function() {
return this._origin.length
};
b.prototype.setFullLength =
function(a) {
if (typeof a != "number" && (a = parseInt(a, 10), isNaN(a))) throw new TypeError("Cannot set possible length to a non-number");
this._actualLen = a;
return this
};
b.prototype.getFullLength = function() {
return this._actualLen != void 0 ? Math.max(this._actualLen, this.getLength()) : this.getLength()
};
b.prototype.append = function(a) {
if (!a) return this;
if (this._resolved) Spotify.App.trigger("track_multi_metadata", [a], function(b) {
var c = this._origin.push(a) - 1;
this._metadata.push(b[a]);
this._shuffled && this._shuffle(c)
}.bind(this));
else {
var b = this._origin.push(a) - 1;
this._shuffled && this._shuffle(b)
}
return this
};
b.prototype.appendWithMeta = function(a, b) {
if (!a || !b) return this;
var c = this._origin.push(a) - 1;
this._metadata[c] = b;
this._shuffled && this._shuffle(c);
return this
};
b.prototype.concat = function(a) {
if (!a || !a.length) return this;
if (this._resolved) Spotify.App.trigger("track_multi_metadata", a, function(b) {
for (var c = 0, g = a.length; c < g; c++) this._origin.push(a[c]), this._metadata.push(b[a[c]]);
this._shuffled && this._shuffle(this._origin.length - a.length - 1)
}.bind(this));
else {
for (var b = 0, c = a.length; b < c; b++) this._origin.push(a[b]);
this._shuffled && this._shuffle(this._origin.length - a.length - 1)
}
return this
};
b.prototype.splice = function(a, b) {
if (typeof a == "undefined" || !b || !b.length) return this;
if (this._resolved) Spotify.App.trigger("track_multi_metadata", b, function(c) {
for (var g = [a, b.length], d = [a, b.length], i = 0, f = b.length; i < f; i++) i in b && b[i] && (g.push(b[i]), d.push(c[b[i]]));
this._origin.splice.apply(this._origin, g);
this._metadata.splice.apply(this._metadata, d);
this._shuffled && this._shuffle(a)
}.bind(this));
else {
for (var c = [a, b.length], g = 0, d = b.length; g < d; g++) g in b && b[g] && c.push(b[g]);
this._origin.splice.apply(this._origin, c);
this._shuffled && this._shuffle(a)
}
};
b.prototype.trim = function(a, b) {
var c = this._origin;
if (c[a] != b) return !1;
a += 1;
var g = c.length;
c.splice(a, g);
this._resolved && this._metadata.splice(a, g);
this._shuffled && this._shuffle();
return !0
};
b.prototype.insert = function(a, b, c) {
if (!c) return !1;
typeof c == "string" && (c = [c]);
var g = this._origin;
if (g[a] != b) return !1;
this._resolved ? Spotify.App.trigger("track_multi_metadata", c, function(d) {
g.splice.apply(g, [a, 1, b].concat(c));
for (var i = [], f = 0, h = c.length; f < h; f++) i.push(d[c[f]]);
this._metadata.splice.apply(this._metadata, [a + 1, 0].concat(i))
}.bind(this)) : g.splice.apply(g, [a, 1, b].concat(c));
return !0
};
b.prototype.remove = function(a, b) {
if (!b) return !1;
var c = this._origin;
if (c[a] != b) return !1;
c.splice(a, 1);
this._resolved && this._metadata.splice(a, 1);
this._shuffled && this._shuffle();
return !0
};
b.prototype.clear = function() {
var a =
this._origin,
b = this._metadata;
a.splice(0, a.length);
b.splice(0, b.length);
return this
};
b.prototype.hasRange = function(a, b) {
var c = this._origin;
if (a < 0) return !1;
if (b >= c.length) return !1;
for (var c = c.slice(a, b), g = c.length; g--;) if (!(g in c)) return !1;
return !0
};
b.prototype.slice = function(a, b) {
return this._origin.slice(a, b)
};
b.prototype.indexOf = function(a) {
return this._list.indexOf(a)
};
b.prototype.getIndex = function() {
return this._rule.indexing ? this._currentIndex : 0
};
b.prototype.getPlayingIndex = function() {
return this._shuffled ? this._shuffledList[this._currentIndex] : this._currentIndex
};
b.prototype.startFrom = function(a) {
var b = a.track;
if (this._shuffled) {
a = this._shuffledList;
if (b == -1) {
do b = Math.floor(Math.random() * a.length);
while (b >= a.length)
}
for (var c = a.length; c--;) if (a[c] === b) {
b = a[0];
a[0] = a[c];
a[c] = b;
this._currentIndex = 0;
break
}
} else this._currentIndex = b == -1 ? 0 : b;
return this
};
b.prototype.current = function() {
var a = this._shuffled ? this._list[this._currentIndex] : this._currentIndex;
return {
item: this._origin[a],
metadata: this._metadata[a]
}
};
b.prototype.shift = function() {
var a = this._shuffled ? this._list[this._currentIndex] : this._currentIndex;
if (!this._origin[a]) return null;
var b = {
item: this._origin[a],
metadata: this._metadata[a]
};
this._origin.splice(a, 1);
this._metadata.splice(a, 1);
this._shuffled && this._list.splice(this._currentIndex, 1);
return b
};
b.prototype.next = function() {
if (!this._rule.next) return !1;
var a = ++this._currentIndex,
b = this._origin;
if (this._repeated) {
if (a >= b.length) a = this._currentIndex = 0;
this._shuffled && (a = this._shuffledList[a]);
return {
item: b[a],
metadata: this._metadata[a]
}
} else if (a < b.length) return this._shuffled && (a = this._shuffledList[a]), {
item: b[a],
metadata: this._metadata[a]
};
this._currentIndex--;
return null
};
b.prototype.previous = function() {
if (!this._rule.previous) return !1;
var a = --this._currentIndex,
b = this._origin;
if (this._repeated) {
if (a < 0) a = this._currentIndex = b.length - 1;
this._shuffled && (a = this._shuffledList[a]);
return {
item: b[a],
metadata: this._metadata[a]
}
} else if (a >= 0) return this._shuffled && (a = this._shuffledList[a]), {
item: b[a],
metadata: this._metadata[a]
};
this._currentIndex++;
return null
};
b.prototype._loader = null;
b.prototype.setLoader = function(a) {
if (typeof a != "function") return this;
this._loader = a;
return this
};
b.prototype._requestContents = function(a, b) {
return !this._loader || this._origin.length == this.getFullLength() ? b.call(this) : this._loader.call(this, this, a.track, b.bind(this))
};
b.prototype._resolved = !1;
b.prototype._resolvePartial = function(a, b, c, g, d) {
for (var i = this._metadata, f = a.length; f--;) i[a[f].idx] = d[a[f]];
this._resolved = !0;
if (!b) return this;
c(this);
this._requestMeta(b, null, null, g)
};
b.prototype._requestMeta = function(a, b, c, g) {
Spotify.App.trigger("track_multi_metadata", a, this._resolvePartial.bind(this, a, b, c, g), g.bind(null))
};
b.prototype._resolve = function(a, b, c) {
b = b ||
function() {};
c = c ||
function() {};
if (this._resolved) return b(this);
var a = a == -1 ? 0 : a || 0,
g = this._origin,
d = this._shuffledList,
i = Math.max(a - 7, 0),
f, h, l, n = [];
if (this._shuffled) {
for (f = 0, h = d.length; f < h; f++) l = new String(g[d[f]]), l.idx = d[f], d[f] == a ? (d.unshift(d.splice(f, 1).pop()), n.unshift(l)) : n.push(l);
i = this._currentIndex = 0
} else
for (f = 0, h = g.length; f < h; f++) l = new String(g[f]), l.idx = f, n.push(l);
this._requestMeta(n.splice(i, 15), n, b, c)
};
b.prototype.resolve = function(a, b, c) {
this._requestContents(a, this._resolve.bind(this, a.track, b, c))
};
var l = Spotify.App.WeakMap;
a.prototype.setExpiry = b.prototype.setExpiry;
a.prototype.isExpired = b.prototype.isExpired;
a.prototype.getContext = function(a) {
a = a != void 0 ? a : this._currentContext;
return this._shuffled ? this._contexts[this._shuffledContexts[a]] : this._contexts[a]
};
a.prototype.getContextIds = function() {
var a = [],
b = this._contexts,
c = b.length;
if (!c) return a;
for (; c--;) a[c] = b[c].getId();
return a
};
a.prototype.setRule = function(a) {
return (a = n[a]) ? (this._rule = a, !0) : !1
};
a.prototype.getRule = function() {
return this.getContext().getRule()
};
a.prototype.setShuffle = function(a) {
if (!this._rule.shuffle) return !1;
(this._shuffled = a) ? this._shuffle() : this._unshuffle();
return a
};
a.prototype.isShuffled = function() {
return this._shuffled
};
a.prototype.setRepeat = function(a) {
return !this._rule.repeat ? !1 : this._repeated = a
};
a.prototype.isRepeated = function() {
return this._repeated
};
a.prototype.startFrom = function(a) {
var b = a.context;
if (this._shuffled) {
var c = this._shuffledContexts;
if (b == -1) {
do b = Math.floor(Math.random() * c.length);
while (b >= c.length)
}
for (var g = c.length; g--;) if (c[g] === b) {
b = c[0];
c[0] = c[g];
c[g] = b;
this._currentContext = 0;
break
}
} else this._currentContext = b == -1 ? 0 : b;
(c = this.getContext()) && c.startFrom(a);
return this
};
a.prototype._shufflePartial = function(a) {
var b = this._shuffledContexts;
if (!b) return this;
for (var g = this._contexts, d = g.length - a, i = Array(d); d--;) {
var f = g[a + d];
f && f.setShuffle(!0);
i[d] = a + d
}
c(i).unshift(a, 0);
b.splice.apply(b, i)
};
a.prototype._shuffle = function(a) {
if (a != void 0) return this._shufflePartial(a);
for (var b = this._contexts.slice(0), a = this._shuffledContexts = [], g = 0, d = b.length; g < d; g++) b[g].setShuffle(!0), a.push(g);
b = a.splice(this._currentContext, 1).pop();
c(a).unshift(b);
this._currentContext = 0;
this._noReset.clear();
this._noReset.set(this.getContext(), !0);
return this
};
a.prototype._unshuffle =
function() {
this._currentContext = this._shuffledContexts[this._currentContext];
for (var a = this._contexts.slice(0), b = 0, c = a.length; b < c; b++) a[b].setShuffle(!1);
this._noReset.clear();
return this
};
a.prototype.append = function(a) {
this._contexts.push(a.unwrap());
this._resolved && a.resolve({
track: 0,
context: 0
});
this._shuffled && this._shuffle(this.length - 1);
return this
};
a.prototype.concat = function(a) {
if (!a || !a.length) return this;
for (var b = 0, c = a.length; b < c; b++) this._contexts.push(a[b].unwrap()), this._resolved && a[b].resolve({
track: 0,
context: 0
});
this._shuffled && this._shuffle(this._contexts.length - a.length)
};
a.prototype.splice = function(a, b) {
if (typeof a == "undefined" || !b || !b.length) return this;
for (var c = [a, b.length], g = 0, d = b.length; g < d; g++) g in b && b[g] && (c.push(b[g].unwrap()), this._resolved && b[g].resolve({
track: 0,
context: 0
}));
this._contexts.splice.apply(this._origin, c);
this._shuffled && this._shuffle(a)
};
a.prototype.insert = function(a, b, c) {
if (!c) return !1;
var g = this._contexts,
b = b.unwrap(),
c = c.unwrap();
if (g[a] != b) return !1;
g.splice(a, 1, b, c);
this._resolved && c.resolve({
track: 0,
context: 0
});
return !0
};
a.prototype.remove = function(a, b) {
if (!b) return !1;
var c = this._contexts,
b = b.unwrap();
if (c[a] != b) return !1;
c.splice(a, 1);
this._shuffled && this._shuffle();
return !0
};
a.prototype.clear = function() {
var a = this._contexts;
a.splice(0, a.length);
return this
};
a.prototype.slice = function(a, b) {
return this._contexts.slice(a, b)
};
a.prototype.get = function(a) {
for (var b = this._contexts, c = 0, g = b.length; c < g; c++) {
var d = b[c],
i = d.getLength();
if (i < a) a -= i;
else
return d.get(a)
}
return null
};
a.prototype.current = function() {
return this.getContext().current()
};
a.prototype.getIndex = function(a) {
var b = this.getContext().getIndex();
if (!a) return b;
for (var a = this._currentContext, c = this._contexts, g = 0; g != a; g++) b += c[g]._origin.length;
return b
};
a.prototype.getPlayingIndex = function() {
return this.getContext().getPlayingIndex()
};
a.prototype.getContextIndex = function() {
return this._shuffled ? this._shuffledContexts[this._currentContext] : this._currentContext
};
a.prototype.getLength = function(a) {
if (!a) return this.getContext().getLength();
for (var a = 0, b = this._contexts.length; b--;) a += this._contexts[b]._origin.length;
return a
};
a.prototype.getFullLength = function() {
return this.getContext().getFullLength()
};
a.prototype.getContextsLength = function() {
return this._contexts.length
};
a.prototype.previous = function() {
if (!this._rule.previous) return !1;
var a = this._contexts,
b = a.length,
c = null,
g;
if (this._shuffled) for (var d = this._noReset; b--;) {
g = --this._currentContext;
if (g < 0) g = this._currentContext = a.length - 1;
g = a[this._shuffledContexts[g]];
if (!g) return null;
if (this._repeated && g._currentIndex == 0) g._currentIndex = g.getLength();
d.get(g) || (g._currentIndex++, d.set(g, !0));
if (c = this.getContext().previous()) break
} else
for (; b--;) {
if (c = this.getContext().previous()) break;
g = --this._currentContext;
if (g < 0) {
if (!this._repeated) {
this._currentContext++;
break
}
g = this._currentContext = a.length - 1
}
g = a[g];
if (!g) return null;
g._currentIndex = g.getLength()
}
return c
};
a.prototype.next = function() {
if (!this._rule.next) return !1;
var a = this._contexts,
b = a.length,
c = null,
g;
if (this._shuffled) for (var d =
this._noReset; b--;) {
g = ++this._currentContext;
if (g >= a.length) g = this._currentContext = 0;
next = a[this._shuffledContexts[g]];
if (!next) return null;
if (this._repeated && next._currentIndex == next.getLength() - 1) next._currentIndex = -1;
d.get(next) || (next._currentIndex--, d.set(next, !0));
if (c = this.getContext().next()) break
} else
for (; b--;) {
if (c = this.getContext().next()) break;
g = ++this._currentContext;
if (g >= a.length) {
if (!this._repeated) {
this._currentContext--;
break
}
g = this._currentContext = 0
}
next = a[g];
if (!next) return null;
next._currentIndex = -1
}
return c
};
a.prototype.getId = function() {
return this.getContext().getId()
};
a.prototype.resolve = function(a, b, c) {
this.startFrom(a);
var g = this._contexts;
if (this._resolved) return b();
this.getContext().resolve(a, function() {
this._resolved = !0;
b();
for (var c = g.length; c--;) g[c].resolve(a)
}.bind(this), c)
};
g.prototype.getOwner = function() {
return this._owner
};
g.prototype.unwrap = function() {
return this._context
};
g.prototype.setOwner = function(a) {
if (a) this._owner = a;
return this
};
g.prototype.isContext =
function() {
return this._context instanceof b
};
g.prototype.isContextGroup = function() {
return this._context instanceof a
};
for (var m in b.prototype)(function(a) {
g.prototype[a] = function() {
var b = this._context,
c = b[a];
if (!c) throw Error('Context object has no method "' + a + '"');
c = c.apply(b, arguments);
return c == b ? this : c
}
})(m)
})();
(function() {
function d(b) {
f.call(this);
delete Spotify.App.ContextPlayer;
this._available = this._uid = 0;
this._previous = {};
this._incoming = {};
this.player = b.player;
this.logging = b.logging.endSong;
this._intercept = !1;
this._interceptions = this._intercepted = null;
this._queue = [];
this._history = [];
this.setup()
}
var h = Spotify.Link,
f = Spotify.App.EventEmitter,
b = [].slice;
d.prototype = new f;
d.prototype.constructor = d;
Spotify.App.ContextPlayer = d;
d.prototype.setup = function() {
var b = this.player;
b.onPlay = this.onPlay.bind(this);
b.onPause = this.onPause.bind(this);
b.onTrackEnded = this.onEnded.bind(this);
b.onInvalidTrackUri = b.onPlaybackFailed = this.onInvalid.bind(this)
};
d.prototype.onPlay = function() {
this._available++;
this._keepPlay && this.player.resume();
delete this._keepPlay;
this.fireEvent("play");
var b = this.player.trackUri,
a = this._incoming[b];
delete this._incoming[b];
a && setTimeout(a.bind(this), 10)
};
d.prototype.onPause = function() {
this.fireEvent("pause")
};
d.prototype.onEnded = function() {
delete this._keepPlay;
this.fireEvent("ended");
this._playIntercepted() || this.next(!0)
};
d.prototype.onInvalid = function(b) {
delete this._keepPlay;
var a = b.params.data,
g = this._incoming[a];
delete this._incoming[a];
g && setTimeout(g.bind(this, "unplayable"), 10);
a = this.next.bind(this, !0, function(a) {
if (!(a !== "no-context" || a !== "forbidden" || a !== "no-tracks")) a = this._previous, this._currentContext = a.context, this._currentTrack = a.track, this._currentGroup = a.group
}.bind(this));
b.params.domain !== 12 && b.params.code !== 8 && a()
};
d.prototype._shuffled = !1;
d.prototype.setShuffle =
function(b) {
this._shuffled = b = !! b;
var a = this._currentContext;
a && a.setShuffle(b);
return !0
};
d.prototype._repeated = !1;
d.prototype.setRepeat = function(b) {
this._repeated = b = !! b;
var a = this._currentContext;
a && a.setRepeat(b);
return !0
};
d.prototype.setVolume = function(b) {
if (typeof b != "number") return !1;
this.player.setVolume(b);
return !0
};
d.prototype.getState = function(b) {
var a = this.player.getPlayerState(),
g = this._currentContext,
a = {
__uid: this._uid,
__index: g ? g.getIndex(!0) : null,
__length: g ? g.getLength(!0) : null,
__rules: g ? g.getRule() : {},
__owner: g ? g.getOwner() : null,
playing: this._keepPlay ? !0 : !a.isPaused && !a.isStopped,
context: {
uri: g ? g.getId() : null
},
index: !g ? null : g.getPlayingIndex(),
track: this._currentTrack || {
uri: null
},
position: a.position,
duration: a.duration || 0,
volume: a.volume,
repeat: g ? g.isRepeated() : this._repeated,
shuffle: g ? g.isShuffled() : this._shuffled
};
if (b && (a.__group = null, g && g.isContextGroup())) b = g._context, a.__group = {
id: b._id,
index: b.getContextIndex(),
array: b.getContextIds()
};
return a
};
d.prototype._currentGroup =
null;
d.prototype._currentContext = null;
d.prototype._currentTrack = !1;
d.prototype.togglePlay = function() {
this.player.playpause();
return !0
};
d.prototype.resume = function() {
this.player.resume();
return !0
};
d.prototype.pause = function() {
this.player.pause();
return !0
};
d.prototype.seek = function(b) {
if (typeof b != "number" || !this._currentContext || !this._currentContext.getRule().seek) return !1;
this.player.seek(b);
return !0
};
d.prototype.queue = function(b) {
if (!b) return !1;
head ? this._queue.unshift(queue) : this._queue.push(queue);
b.resolve({
track: 0,
context: 0
});
return !0
};
d.prototype.intercept = function() {
this._intercept = !0;
return this
};
d.prototype.setIntercept = function(b) {
if (!b) return !1;
this._interceptions = b;
return !0
};
d.prototype._getIntercept = function() {
if (!this._intercept || !this._interceptions) return null;
this._intercept = !1;
var b = this._interceptions.shift();
if (!b) return null;
var a = h.fromString(b.item),
b = b.metadata;
if (!b || !b.playable && !b.__pid) return null;
b.uri = a.toURI();
return {
item: (a.type == "ad" ? h.adLink(b.__pid) : h.trackLink(b.__pid)).toURI(),
metadata: b,
context: this._interceptions
}
};
d.prototype._playIntercepted = function() {
if (!this._intercepted) return !1;
var b = this._intercepted;
delete this._intercepted;
this._attemptPlay.apply(this, b);
return !0
};
d.prototype.next = function(b, a) {
var g = this._currentContext;
if (!this._available && this._repeated) return this.createEndLog("endplay", g), this;
if (!g) return a && a.call(this, "no-context"), this;
var d = g.next();
do
if (d) {
var f = d.item,
l = d.metadata;
if (l && (l.playable || l.__pid)) break
}
while (d = g.next());
if (!d) {
if (d === !1) return a && a.call(this, "forbidden"), this;
this.createEndLog("endplay", g);
a && a.call(this, "no-tracks");
return this.reset()
}
l.uri = f;
f = h.trackLink(l.__pid).toURI();
d = b ? "trackdone" : "nextbtn";
this.fireEvent("beforeNext", [f, l, g], !0);
this.createEndLog(d, g);
this._attemptPlay(d, f, l, g);
this.fireEvent("next", [f, l, g]);
a && a.call(this)
};
d.prototype.previous = function(b, a) {
var g = this._currentContext;
if (!g) return a && a.call(this, "no-context"), this;
var d = g.previous();
do
if (d) {
var f = d.item,
l = d.metadata;
if (l && (l.playable || l.__pid)) break
}
while (d = g.previous());
if (!d) {
if (d === !1) {
a && a.call(this, "forbidden");
return
}
this.createEndLog("endplay", g);
a && a.call(this, "no-tracks");
return this.reset()
}
l.uri = f;
f = h.trackLink(l.__pid).toURI();
d = b ? "trackdone" : "backbtn";
this.fireEvent("beforePrevious", [f, l, g], !0);
this.createEndLog(d, g);
this._attemptPlay(d, f, l, g);
this.fireEvent("previous", [f, l, g]);
a && a.call(this)
};
d.prototype.play = function(b, a, g) {
b.setRepeat(this._repeated);
b.setShuffle(this._shuffled);
b.startFrom(a);
b.resolve(a, this._parseContext.bind(this, b, a, g), (g ||
function() {}).bind(null, "metadata-error"))
};
d.prototype._locatePlayable = function(b) {
for (var a = 0, g = b.getLength(!0); a < g; a++) {
var d = b.get(a);
if (d && (track = d.item, metadata = d.metadata, metadata.playable || metadata.__pid)) return b._context._currentIndex = a, d
}
return null
};
d.prototype._parseContext = function(b, a, g) {
var d = !1;
a.track == -1 && (d = !0);
var f, l = !d ? b.current() : this._locatePlayable(b);
if (!l) return g("no-playables");
var m = function(d, i) {
i.uri = d;
var f = h.trackLink(i.__pid);
this._available = b.getLength(!0);
this.fireEvent("beforeContextChange", [f, i, b], !0);
this.createEndLog(a.reason || "clickrow", b);
this._attemptPlay(a.reason || "clickrow", f, i, b, g, a.ms, a.pause);
this.fireEvent("contextChange", [f, i, b])
}.bind(this),
d = l.item;
f = l.metadata;
if (!f || !f.playable && !f.__pid) return g("unplayable", l.item);
m(d, f)
};
d.prototype._playTrigger = null;
d.prototype._attemptPlay = function(c, a, g, d, f, l, m) {
a instanceof h && (a = a.toURI());
this.fireEvent("beforePlay", [a, g, d]);
this.createLog(c, g.uri, d);
if (this._intercepted) return this._intercepted =
b.call(arguments), this.fireEvent("intercepted", [a, g, d]), this;
var o = this._getIntercept();
o ? (this._intercepted = b.call(arguments), a = o.item, g = o.metadata, d = o.context) : this._incoming[a] = f;
this._previous = {
context: this._currentContext,
track: this._currentTrack,
group: this._currentGroup
};
this._currentContext = d;
this._currentTrack = g;
this.player.pause();
this._keepPlay = !m;
l = isNaN(l) || l < 0 ? 0 : l;
this._available--;
this._playTrigger ? (clearTimeout(this._playTrigger), this._playTrigger = setTimeout(function() {
this._uid++;
this.player.load(a, l, !m);
delete this._playTrigger
}.bind(this), 1E3)) : (this._playTrigger = 1, this._uid++, this.player.load(a, l, !m))
};
d.prototype.createLog = function(b, a, g) {
var d = "",
f = "unknown",
l = g.getOwner(),
m = h.fromString(l);
if (g && m.id != "search" && m.id != "radio") {
if (g = g.getId()) g = h.fromString(g), d = g.toURI(), f = g.type
} else if (m.id == "search" || m.id == "radio") d = l, source_end = f = m.id;
b = {
display_track: a,
play_context: d,
source_start: f,
reason_start: b,
referrer: l,
referrer_version: "0.1.0",
referrer_vendor: "com.spotify"
};
this._started = !0;
this.logging.setEndSongStartLog(b);
return b
};
d.prototype.createEndLog = function(b, a) {
if (!this._started) return this;
var g = "unknown",
d = a.getOwner(),
d = h.fromString(d);
if (a && d.id != "search" && d.id != "radio") {
if (d = a.getId()) h.fromString(d).toURI(), g = h.fromString(d).type
} else if (d.id == "search" || d.id == "radio") g = d.id;
g = {
source_end: g,
reason_end: b
};
this.logging.setEndSongStopLog(g);
return g
};
d.prototype.reset = function() {
this._currentGroup = this._currentContext = this._currentTrack = null;
this._playTrigger && clearTimeout(this._playTrigger);
delete this._playTrigger;
this.player.stop();
this.fireEvent("reset")
}
})();
(function() {
function d(a, b) {
this.timestamp = (new Date).getTime();
this._internal = !1;
this._timeout = !0;
this._sent = !1;
this._uid = a;
this._data = {
id: b,
success: !0,
payload: null
}
}
function h(a, b, c) {
return function() {
if (!this._ready) return this.queue();
a[c].fn = b;
return b.apply(this, arguments)
}
}
function f(a) {
for (var b in a) if (a.hasOwnProperty(b)) {
var c = b,
g = a[b];
switch (!0) {
case c == "flushRequests":
u.push(g.bind(this));
break;
case !! (matches = c.match(/^@(@)?(.*)$/)):
var d = matches[1] ? k : o,
c = matches[2];
if (c in d) throw Error('Redefinition of message handler "' + c + '".');
if (typeof g == "string") {
if (g = d[g]) d[c] = g;
else
throw Error('Aliasing of undefined message handler "' + c + '".');
break
}
d[c] = {
fn: h(d, g, c),
bound: this,
reply: !0
};
break;
default:
this[c] = g
}
}
this._queue = [];
this.create && this.create();
if (this.init) Spotify.App.onReady(this.init.bind(this));
return this
}
function b() {
if (v.length) {
var a = (new Date).getTime(),
c = v.first;
do {
var g = c.value;
if (a - g.timestamp < w) break;
g.timeout();
g = c.next;
v.remove(c)
} while (c = g)
}
setTimeout(b, w)
}
function c(b) {
var c = b.data;
if (typeof c == "string") try {
c =
JSON.parse(c)
} catch (i) {
return this
}
var h = c.uid = q++,
k = b.source,
b = b.origin;
c.origin = b;
c.source = k;
p[h] = {
origin: b,
source: k,
timestamp: (new Date).getTime()
};
k = new d(c.uid, c.id);
k._type = c.name;
if (c.name == "core_flush") return f.flush(), k.send(!0);
a && (b = l(b)) && m.enter(b, h, c.name, c.args);
h = o[c.name];
if (!h) return k.fail("not-implemented", "API not implemented.");
v.append(new g.Node(k));
h.fn.call(h.bound || {}, c, k)
}
var a = !1,
a = !0,
g = Spotify.LinkedList,
i = Spotify.App.SourceURLs,
n = Spotify.Utils.isArray,
l = Spotify.App.extractAppName,
m = window._bridge_logs = new Spotify.App.RequestLogger,
o = {},
k = {},
p = {},
q = 0,
s = {},
u = [];
d.prototype.internal = function(a, b) {
this._internal = !0;
this._data.done = a;
this._data.error = b;
return this
};
d.prototype.persist = function() {
this._timeout = !1;
return this
};
d.prototype.send = function(b) {
if (this._sent) return null;
var c = this._data,
g;
if (this._internal)(c.success ? c.done : c.error)(b);
else {
g = p[this._uid];
if (!g) return null;
delete p[this._uid];
if (g.source) {
if (b.type) {
if (b.data) b.event = b.type;
if (b.receiver) b.target = b.receiver
}
c.payload =
b;
g.source.postMessage(JSON.stringify(c), g.origin);
a && (c.success ? m.succeed(this._uid, "success") : m.fail(this._uid, c.payload ? c.payload.error : "unknown-error"))
}
}
delete this._data;
this._sent = !0;
return null
};
d.prototype.fail = function(a, b, c) {
a = typeof a == "string" ? {
error: a,
message: b,
code: c
} : a;
if (this._sent) return null;
this._data.success = !1;
return this.send(a)
};
d.prototype.timeout = function() {
if (this._sent || !this._timeout) return !1;
this._data.success = !1;
return this.send({
error: "timeout",
message: "Request timed-out."
})
};
Spotify.App.Responder = f;
f.respondsTo = function(a) {
return a in o
};
f.prototype.traceOut = function() {
return function() {}
};
f.prototype.traceError = function() {
return function() {}
};
f.flush = function() {
for (var a = u.length; a--;) u[a]()
};
f.prototype.use = function(a) {
var b = 0,
c = [],
g;
for (g in a) this[g] = a[g], c.push(a[g]), b++;
a = function() {
--b || this.start()
}.bind(this);
for (g = b; g--;) c[g].onReady(a, this);
return this
};
f.prototype.queue = function() {
var a = this.queue.caller;
this._queue.push({
fn: a,
args: a.arguments
})
};
f.prototype.unqueue =
function() {
for (var a = this._queue, b = 0, c = a.length; b < c; b++) {
var g = a[b];
g.fn.apply(this, g.args)
}
this._queue = [];
return this
};
f.prototype.store = function(a, b, c) {
(s[b] || (s[b] = new Spotify.SimpleCache(1E3))).put(a, c);
return this
};
f.prototype.retrieve = function(a, b) {
return s[b] ? s[b].get(a) || null : null
};
f.prototype.trigger = function(a, b, c, g) {
a = o[a] || k[a];
if (!a) return typeof g !== "undefined" ? g({
error: "not-implemented"
}) : null;
n(b) && (b = {
args: b
});
a.fn.call(a.bound || {}, b, (new d(null, null)).internal(c, g))
};
Spotify.App.trigger =
f.prototype.trigger;
f.prototype.createImageSizes = function(a, b) {
var c = [
[60, i.tiny + a],
[120, i.small + a],
[300, i.normal + a],
[640, i.large + a]
];
b && (c.shift(), c.pop());
return c
};
f.prototype.createSnapshot = function(a, b, c, g) {
var d = a[1] || 0,
a = a[2] || -1,
a = a == -1 ? b.length : a;
return {
range: {
offset: d,
length: a
},
length: c || b.length,
array: b.slice(d, d + a),
metadata: (g || []).slice(d, d + a)
}
};
f.prototype.createDimensions = function(a, b, c) {
a = a || 0;
c = c || 500;
b = b == -1 ? c : Math.min(b, c);
return {
start: a,
end: a + b - 1,
length: b
}
};
var w = 3E4,
v = new g;
b();
window.attachEvent && !window.addEventListener ? window.attachEvent("onmessage", c) : window.addEventListener("message", c, !1)
})(this);
(function() {
var d = Spotify.Link,
h = Spotify.LinkedList,
f = Spotify.App.WeakMap,
b = {
artist: !0,
album: !0,
search: !0
};
new Spotify.App.Responder({
_ready: !1,
_frames: new h,
_argCache: new f,
_listeners: new f,
_logData: null,
init: function(b, a) {
if (!a) return this;
var g = this.publisher = a.publisher;
this.logger = b.logging.view;
this.clientLogger = b.logging.clientEvent;
g.subscribe("APPLICATION_STATE_CHANGED", this);
g.subscribe("APPLICATION_DISPOSED", this);
this.setup()
},
setup: function() {
this._ready = !0;
this.unqueue()
},
log: function(b) {
var a =
this._logData,
g = (new Date).getTime();
a && this.logger.log(a.uri, a.version, a.vendor, g - a.timestamp);
this._logData = {
uri: b,
version: "0.1.0",
vendor: "com.spotify",
timestamp: g
}
},
onAppStateChange: function(c) {
var c = c.message,
a = c.iframe;
this._frames.append(new h.Node(a));
var g = c.link,
c = this._argCache.get(a) || [],
d = this.transformArgs(g.id, g.args);
this._argCache.set(a, d);
this.log(g.toURI());
if (b[g.id]) return this;
a = this._listeners.get(a);
if (!a) return this;
var g = {
type: "arguments",
data: {
arguments: d
}
},
f = d.length;
if (f != c.length) return a.send(g);
for (; f--;) if (d[f] != c[f]) return a.send(g)
},
onAppDisposed: function(b) {
for (var a = this._frames, g = a.first, b = b.message.iframe; g;) {
var d = g.next;
b == g.value && a.remove(g);
g = d
}
this._argCache.remove(b);
this._listeners.remove(b)
},
onNotify: function(b) {
switch (b.messageType) {
case "APPLICATION_STATE_CHANGED":
return this.onAppStateChange(b);
case "APPLICATION_DISPOSED":
return this.onAppDisposed(b)
}
},
associateWindow: function(b) {
for (var a = this._frames.first; a;) {
if (a.value && a.value.contentWindow == b) return a.value;
a = a.next
}
return null
},
"@application_open_uri": function(b, a) {
var g;
try {
g = d.fromString(b.args[0]).toAppLink()
} catch (i) {
return a.fail("invalid-uri", "The URI passed is not a valid Spotify URI.")
}
if (g.id == "track") return a.fail("not-implemented", "This URI type is not supported.");
this.publisher.notify("APPLICATION_OPEN_URI", {
link: g,
origin: this.associateWindow(b.source),
replace: !! b.args[1]
});
return a.send(!0)
},
extractName: function(b) {
return b.match(/^https?:\/\/[A-Za-z0-9]{40}-([A-Za-z0-9_-]+).*/)
},
transformArgs: function(b, a) {
a = a.slice(0);
if (b == "user" || b == "playlist") switch (a[1]) {
case "playlist":
a = [a[0], a[2]];
break;
case "starred":
a = [a[0], "starred"];
break;
case "toplist":
a = [a[0], "toplist"];
break;
case "top":
a = [a[0], "top", a[2]]
}
for (var g = a.length; g--;) a[g] = encodeURIComponent(a[g]);
return a
},
"@application_query": function(b, a) {
var g = this._argCache.get(this.associateWindow(b.source));
a.send({
arguments: g || []
})
},
"@application_event_wait": function(b, a) {
this._listeners.set(this.associateWindow(b.source), a.persist())
},
"@application_client_event": function(b, a) {
var g = this.extractName(b.origin);
if (!g) return a.fail("invalid-uri", "The origin of the request is not a valid application.");
var g = d.applicationLink(g[1], this._argCache.get(this.associateWindow(b.source)) || []),
i = b.args;
try {
this.clientLogger.log({
source: g.toURI(),
source_version: "0.1.0",
source_vendor: "com.spotify",
context: i[0].toString(),
event: i[1].toString(),
event_version: i[2].toString(),
test_version: i[3].toString(),
data: JSON.stringify(i[4])
})
} catch (f) {
return a.fail("invalid-request", "Check your logging arguments.")
}
return a.send(!0)
},
"@application_get_uri": function(b, a) {
var g = this.extractName(b.args[0]);
if (!g) return a.fail("invalid-uri", "The origin of the request is not a valid application.");
var g = g[1],
i = this._argCache.get(this.associateWindow(b.args[1])) || [];
a.send(d.applicationLink(g, i).toURI())
},
"@application_get": function(b, a) {
var g = this.extractName(b.args[0]);
if (!g) return a.fail("invalid-uri", "The origin of the request is not a valid application.");
for (var g = g[1], i = this._argCache.get(this.associateWindow(b.args[1])) || [], f = i.length; f--;) i[f] = decodeURIComponent(i[f]);
a.send({
uri: d.applicationLink(g, i).toURI(),
frame: this.associateWindow(b.args[1])
})
},
"@application_set_title": function(b, a) {
var g = b.args[0];
document.title = !g || !g.replace(/^\s+|\s+$/g, "") ? "Spotify" : g + " - Spotify";
return a.send(!0)
}
})
})();
(function() {
new Spotify.App.Responder({
_ready: !1,
init: function(d) {
this.service = d.hermes;
this.start()
},
start: function() {
this._ready = !0;
this.unqueue()
},
sendSchemaId: function(d, h) {
d.send({
id: h
})
},
handleErrors: function(d, h) {
return d.fail("hermes", "Hermes error", h)
},
"@hermes_register_schema": function(d, h) {
this.service.loadSchemas(this.resolveSchemas(d.args, d.deps), "proto", this.sendSchemaId.bind(this, h), this.handleErrors.bind(this, h))
},
resolveSchemas: function(d, h) {
if (!h) return d;
for (var f = h["static"], b =
f.replace(/\/([^\/]*)$/, ""), c = [], a = 0, g = d.length; a < g; a++) {
var i = d[a];
if (!/^\/static/.test(i)) {
var n = i.match(/^\$([a-z\-\_]+)(\/.*)/),
l = !1,
m, o = !1;
n ? (l = n[1], m = n[2]) : /^\//.exec(i) && (o = !0);
l && h[l] ? i = h[l] + m : (l ? i = "/" + l + m : o || (i = "/" + i), i = (l ? b : f) + i)
}
c.push(i)
}
return c
},
sendResponse: function(d, h) {
d.send({
result: h
})
},
"@hermes_send_request": function(d, h) {
var f = d.args;
this.service.send(f[0], f[1], f[3], f[2], f[4], this.sendResponse.bind(this, h), this.handleErrors.bind(this, h))
}
})
})();
(function() {
new Spotify.App.Responder({
_ready: !1,
_modifiers: {
alt: 1,
meta: 2,
ctrl: 8
},
_keymap: {
32: 16,
37: 32,
38: 64,
39: 128,
40: 256,
83: 512
},
_ignore: {
input: 1,
button: 1,
textarea: 1,
select: 1
},
_bindings: {},
_empty: function() {},
init: function(d) {
this.core = d;
this._setupBindings();
window.addEventListener("keydown", this.handleOwn.bind(this, !1));
window.addEventListener("keyup", this.handleOwn.bind(this, !0))
},
_setupBindings: function() {
var d = this._bindings,
h = this._modifiers,
f = this._keymap;
d[f[32]] = "player_play_toggle";
d[f[37] | h.ctrl | h.alt] = "player_skip_to_prev";
d[f[39] | h.ctrl | h.alt] = "player_skip_to_next";
d[f[38] | h.ctrl | h.alt] = "player_volume_up";
d[f[40] | h.ctrl | h.alt] = "player_volume_down";
d[f[83] | h.ctrl | h.alt] = "navigation_show_search";
this._ready = !0;
this.unqueue()
},
handleOwn: function(d, h) {
if (this._ignore[h.target.tagName.toLowerCase()]) return this;
var f = this._keymap[h.which || h.keyCode];
if (!f) return this;
var b = this._modifiers;
h.altKey && (f |= b.alt);
h.metaKey && (f |= b.meta);
h.ctrlKey && (f |= b.ctrl);
f = this._bindings[f];
if (!f) return this;
h.preventDefault();
h.stopPropagation();
d && this.trigger(f, {
args: [],
origin: "https://player.spotify.com"
}, this._empty, this._empty)
},
"@keyboard_get_bindings": function(d, h) {
return h.send({
_modifiers: this._modifiers,
_keymap: this._keymap,
_ignore: this._ignore,
_bindings: this._bindings
})
},
"@keyboard_trigger_binding": function(d) {
this.trigger(d.args[0], {
args: [],
origin: d.origin
}, this._empty, this._empty)
},
"@navigation_show_search": function() {
$("nav-search").onmousedown({
preventDefault: this._empty
})
}
})
})();
(function() {
var d = window.navigator;
new Spotify.App.Responder({
_ready: !1,
_hasGeo: !1,
_current: null,
_error: null,
_listeners: [],
init: function() {
this.setup()
},
setup: function() {
if ("geolocation" in d) this._hasGeo = !0;
this._ready = !0;
this.unqueue()
},
notifyListeners: function() {
for (var d = this._listeners.splice(0, this._listeners.length), f = this._error, b = 0, c = d.length; b < c; b++) {
var a = d[b];
f ? a.fail(f.code, f.message) : a.send(this._current)
}
},
positionFailed: function(d) {
var f;
switch (d.code) {
case 1:
d = "permission-denied";
f = "The user has denied access to their location.";
break;
case 3:
d = "timeout";
f = "The request has timed out";
break;
default:
d = "transient", f = "Cannot fetch the location right now"
}
this._error = {
code: d,
message: f
};
this._current = null;
this.notifyListeners()
},
positionFetched: function(d) {
d = d.coords;
this._error = null;
this._current = this.fuzz({
latitude: d.latitude,
longitude: d.longitude,
accuracy: d.accuracy
});
this.notifyListeners()
},
fuzz: function(d) {
return {
latitude: 0.01 * Math.floor(d.latitude * 100),
longitude: 0.01 * Math.floor(d.longitude * 100),
accuracy: d.accuracy
}
},
"@location_query": function(h, f) {
var b = this._error,
c = this._current;
if (b) return f.fail(b.code, b.message);
else if (c) return f.send(c);
else this._listeners.push(f), d.geolocation.watchPosition(this.positionFetched.bind(this), this.positionFailed.bind(this))
}
})
})();
(function() {
var d = Spotify.Link,
h = Spotify.Utils,
f = Spotify.Utils.isArray,
b = Spotify.App.SourceURLs,
c = Spotify.App.RequestBuffer;
new Spotify.App.Responder({
_ready: !1,
_requested: {},
_adRequestBuffer: new c,
_albumRequestBuffer: new c,
_artistRequestBuffer: new c,
_trackRequestBuffer: new c,
create: function() {
this.prepareArtist = this.prepare.bind(this, this.parseArtist);
this.prepareAlbum = this.prepare.bind(this, this.parseAlbum);
this.prepareTrack = this.prepare.bind(this, this.parseTrack);
this.prepareAd = this.prepare.bind(this, this.parseAd)
},
init: function(a) {
this.use({
service: a.metadata,
adchooser: a.adChooser
})
},
start: function() {
this._ready = !0;
this.unqueue()
},
handleError: function(a, b) {
var c, d;
switch (b.code) {
case 400:
case 404:
c = "not-found";
d = "No metadata found for URI.";
break;
default:
c = "transient", d = "Possible issues with the metadata service."
}
return a.fail(c, d)
},
flushRequests: function() {
this.queryService(this._albumRequestBuffer, this.parseAlbum);
this.queryService(this._artistRequestBuffer, this.parseArtist);
this.queryService(this._trackRequestBuffer, this.parseTrack);
this.queryAdService(this._adRequestBuffer, this.parseAd)
},
queryService: function(a, b) {
var c = a.takeIds();
c.length && this.service.lookup(c, this.format.bind(this, b, a, c), this.handleError.bind(this))
},
queryAdService: function(a, b) {
var c = a.takeIds();
c.length && this.adchooser.lookup(c, this.format.bind(this, b, a, c), this.handleError.bind(this))
},
format: function(a, b, c, d) {
f(d) || (d = [d]);
for (var h = 0, m = c.length; h < m; h++) {
var o = c[h],
k = d[h];
this.store(o, "raw", k);
k = k ? a.call(this, o, k) : {
error: "not-found",
message: "Not found."
};
this.store(o, "parsed.metadata", k);
if (a == this.parseTrack && !k.error) this.trigger("starred_track_decorate", [o, k], function(a, c) {
for (var d = b.takeReplies(a), i = d.length; i--;) d[i].send(c)
}.bind(null, o), Spotify.App.noop);
else
for (var o = b.takeReplies(o), p = o.length; p--;) o[p].send(k)
}
},
request: function(a, b, c) {
this.service.lookup(a.slice(0), c.bind(this, a, b), this.handleError.bind(this, b))
},
requestAds: function(a, b, c) {
this.adchooser.lookup(a.slice(0), c.bind(this, a, b), b.fail.bind(b, "unknown", "Ad server Error"))
},
prepare: function(a, b, c, d, h, m) {
f(d) || (d = [d]);
h = c.payload || {};
h.__count = h.__count || d.length;
for (var o = b.length; o--;) {
var k = b[o],
p = d[o];
this.store(k, "raw", p);
p = h[k] = p ? a.call(this, k, p) : null;
this.store(k, "parsed.metadata", p);
h.__count--
}
if (!m && !h.__count) {
delete c.payload;
delete h.__count;
if (a != this.parseTrack) return c.send(h);
this.trigger("starred_tracks_decorate", [h], c.send.bind(c), c.fail.bind(c))
}
},
"@artist_metadata": function(a, b) {
var c = a.args[0];
try {
if (c = d.fromString(c), c.type != "artist") throw Error();
} catch (f) {
return b.fail("invalid-uri", "Not a valid artist URI.")
}
var h = this.retrieve(c, "parsed.metadata");
if (h) return b.send(h);
this._artistRequestBuffer.push(c, b)
},
"@artist_profile": "artist_metadata",
parseArtist: function(a, c) {
var d, f, l = {
name: c.name,
popularity: c.popularity,
image: null,
genres: c.genre ? c.genre.slice() : [],
biography: "",
portraits: []
};
if (c.portrait && c.portrait[0]) d = h.str2hex(c.portrait[0].file_id), l.image = b.normal + d, l.images = this.createImageSizes(d);
if (c.biography) for (var m =
l.portraits, o = c.biography.length; o--;) {
var k = c.biography[o];
l.biography = k ? k.text || "" : "";
if (k.portrait) for (d = 0, f = k.portrait.length; d < f; d++) {
var p = k.portrait[d];
p.size == "DEFAULT" && m.push(b.small + h.str2hex(p.file_id))
}
}
m = c.activity_period || [];
o = [];
for (d = 0, f = m.length; d < f; d++) p = m[d], k = p.start_year || p.decade, p = p.end_year || p.decade + 9, isNaN(p) && (p = (new Date).getFullYear()), o.push({
start: k,
end: p
});
l.years = o.length ? {
from: o[0].start,
to: o[o.length - 1].end
} : null;
return l
},
"@album_metadata": function(a, b) {
var c =
a.args[0];
try {
if (c = d.fromString(c), c.type != "album") throw Error();
} catch (f) {
return b.fail("invalid-uri", "Not a valid album URI.")
}
var h = this.retrieve(c, "parsed.metadata");
if (h) return b.send(h);
this._albumRequestBuffer.push(c, b)
},
"@album_profile": "album_metadata",
parseAlbum: function(a, c) {
var i = d.fromString(a),
f = {
name: c.name,
popularity: c.popularity,
type: (c.type || "").toLowerCase(),
date: c.date || {},
availability: c.availability,
playable: c.playable,
label: c.label
},
l, m, o = c.copyright,
k = f.copyrights = [];
if (o) for (l =
0, m = o.length; l < m; l++) {
var p = o[l];
k[l] = p.text.replace(/^(\([A-Z]+\))?(.*)$/, function(a, b, c) {
return b ? a : "(" + p.type + ") " + c
})
}
o = f.artists = [];
for (l = 0, m = c.artist.length; l < m; l++) o.push({
uri: d.artistLink(c.artist[l].id).toString(),
name: c.artist[l].name
});
o = f.discs = [];
for (l = 0, m = c.disc.length; l < m; l++) k = l + 1, i.disc = k, o.push({
uri: i.toString(),
album: a,
number: k
});
c.cover ? (i = h.str2hex(c.cover[0].file_id), f.image = b.normal + i, f.images = this.createImageSizes(i)) : f.image = null;
return f
},
"@track_metadata": function(a, b) {
var c =
a.args[0];
try {
if (c = d.fromString(c), c.type != "track" && c.type != "ad" && c.type != "local") throw Error();
} catch (f) {
return b.fail("invalid-uri", "Not a valid album URI.")
}
if (c.type == "local") return b.send({
name: c.track || "",
duration: (c.duration || 0) * 1E3,
cover: "",
playable: !1,
album: {
uri: "spotify:empty",
artists: [{
uri: "spotify:empty",
name: c.artist || ""
}],
name: c.album || ""
},
artists: [{
uri: "spotify:empty",
name: c.artist || ""
}]
});
else {
var h = this.retrieve(c, "parsed.metadata");
if (h) return b.send(h);
c.type == "ad" ? this._adRequestBuffer.push(c, b) : this._trackRequestBuffer.push(c, b)
}
},
parseTrack: function(a, c) {
var i = {
__pid: c.playableId,
name: c.name,
disc: c.disc_number,
duration: c.duration,
album: {
uri: d.albumLink(c.album.id).toString(),
name: c.album.name
},
number: c.number,
popularity: c.popularity,
availability: c.availability,
playable: c.playable,
image: null,
starred: !1,
explicit: c.explicit,
advertisement: !! c.ad
};
if (c.album.cover && c.album.cover[0]) i._imgfid = h.str2hex(c.album.cover[0].file_id), i.image = b.normal + i._imgfid, i.images = this.createImageSizes(i._imgfid);
for (var f = i.artists = [], l = 0, m = c.artist.length; l < m; l++) f.push({
uri: d.artistLink(c.artist[l].id).toString(),
name: c.artist[l].name
});
return i
},
"@@track_multi_metadata": function(a, b) {
for (var c = a.args.length, d = {}, f = function(a, f) {
d[a] = f.error ? null : f;
c--;
c || b.send(d)
}, h = 0, o = a.args.length; h < o; h++) {
var k = a.args[h],
p = f.bind(null, k);
this.trigger("track_metadata", [k], p, p)
}
},
parseAd: function(a, c) {
for (var d = {
__pid: c.__pid,
name: c.name,
disc: c.disc,
duration: c.duration,
number: c.number,
popularity: c.popularity,
playable: c.playable,
image: b.normal + c.image,
starred: !1,
explicit: c.explicit,
advertisement: c.advertisement
}, f = d.artists = [], h = 0, m = c.artist.length; h < m; h++) f.push({
uri: c.artist[h].uri,
name: c.artist[h].name
});
return d
},
"@album_tracks_snapshot": function(a, b) {
var c = a.args[0],
d = this.retrieve(c, "parsed.tracks");
if (d) return this.prepareSnapshot(a, b, d);
if (d = this.retrieve(c, "raw")) return d = this.parseAlbumTracks(d), this.store(c, "parsed.tracks", d), this.prepareSnapshot(a, b, d);
this.request([c], b, function(b, g, d) {
this.prepareAlbum(b, g, d, 0, !0);
b = this.parseAlbumTracks(this.retrieve(c, "raw"));
this.store(c, "parsed.tracks", b);
return this.prepareSnapshot(a, g, b)
})
},
"@album_disc_tracks_snapshot": function(a, b) {
var c = a.args[0],
f = this.retrieve(c, "parsed.disc.tracks");
if (f) return this.prepareSnapshot(a, b, f);
var h = d.fromString(c),
m = h.disc;
delete h.disc;
if (f = this.retrieve(h, "raw")) return f = this.parseDiscTracks(f, m), this.store(c, "parsed.disc.tracks", f), this.prepareSnapshot(a, b, f);
this.request([h], b, function(b, g, d) {
this.prepareAlbum(b, g, d, 0, !0);
b = this.parseDiscTracks(this.retrieve(h, "raw"), m);
this.store(c, "parsed.disc.tracks", b);
return this.prepareSnapshot(a, g, b)
})
},
prepareSnapshot: function(a, b, c, d, f) {
if ((!c || !c.length) && f && f.length) for (var c = [], h = f.length; h--;) c[h] = "";
a = this.createSnapshot(a.args, c, d, f);
return b.send(a)
},
parseAlbumTracks: function(a) {
for (var a = a.disc, b = [], c = 0, f = a.length; c < f; c++) for (var h = a[c].track, m = 0, o = h.length; m < o; m++) b.push(d.trackLink(h[m].id).toString());
return b
},
parseDiscTracks: function(a, b) {
b -= 1;
for (var c = a.disc, c = b < c.length ? c[b] : [], f = [], h = 0, m = c.track.length; h < m; h++) f.push(d.trackLink(c.track[h].id).toString());
return f
},
prepareGroup: function(a, b, c, d, f) {
this.prepareArtist(b, c, f, 0, !0);
(c = this.retrieve(b, "raw")) && (c = c[a]);
c = this.parseGroup(c, b);
this.store(b, "parsed." + a, c);
return c
},
parseGroup: function(a) {
var b = [];
if (!a) return b;
for (var c = 0, f = a.length; c < f; c++) {
for (var h = a[c], m = [], o = 0, k = h.length; o < k; o++) {
var p = h[o];
p.playable && m.push({
uri: d.albumLink(p.id).toString()
})
}
b.push({
albums: m
})
}
return b
},
"@artist_albums_snapshot": function(a, b) {
var c = this,
d = a.args[0],
f = this.retrieve(d, "parsed.album_group");
if (f) return this.prepareSnapshot(a, b, [], null, f);
if (f = this.retrieve(d, "raw")) return f = this.parseGroup(f.album_group), this.store(d, "parsed.album_group", f), this.prepareSnapshot(a, b, [], null, f);
this.request([d], b, function(b, g, d) {
b = this.prepareGroup("album_group", b, g, a, d);
return c.prepareSnapshot(a, g, [], null, b)
})
},
"@artist_appearances_snapshot": function(a, b) {
var c = this,
d = a.args[0],
f = this.retrieve(d, "parsed.appears_on_group");
if (f) return this.prepareSnapshot(a, b, [], null, f);
if (f = this.retrieve(d, "raw")) return f = this.parseGroup(f.appears_on_group), this.store(d, "parsed.appears_on_group", f), this.prepareSnapshot(a, b, [], null, f);
this.request([d], b, function(b, g, d) {
b = this.prepareGroup("appears_on_group", b, g, a, d);
return c.prepareSnapshot(a, g, [], null, b)
})
},
"@artist_singles_snapshot": function(a, b) {
var c = this,
d = a.args[0],
f = this.retrieve(d, "parsed.single_group");
if (f) return this.prepareSnapshot(a, b, [], null, f);
if (f = this.retrieve(d, "raw")) return f = this.parseGroup(f.single_group), this.store(d, "parsed.single_group", f), this.prepareSnapshot(a, b, [], null, f);
this.request([d], b, function(b, g, d) {
b = this.prepareGroup("single_group", b, g, a, d);
return c.prepareSnapshot(a, g, [], null, b)
})
},
parseTracks: function(a) {
var b = [];
if (!a || !a.length) return b;
for (var c = 0, f = a.length; c < f; c++) b.push(d.trackLink(a[c].id).toString());
return f == 1 ? b.slice(0) : b.slice(0, Math.min(10, f % 2 ? f - 1 : f))
},
"@artist_top_tracks_snapshot": function(a, b) {
var c = this,
d = a.args[0],
f = this.retrieve(d, "parsed.top_tracks");
if (f) return this.prepareSnapshot(a, b, f);
if (f = this.retrieve(d, "raw")) return f = this.parseTracks(f.top_track), this.store(d, "parsed.top_tracks", f), this.prepareSnapshot(a, b, f);
this.request([d], b, function(b, g, f) {
b = this.parseTracks(f.shift().top_track);
this.store(d, "parsed.top_tracks", b);
return c.prepareSnapshot(a, g, b)
})
},
parseArtists: function(a) {
var c = [],
f = [],
n = {
array: c,
metadata: f
};
if (!a) return n;
for (var l = 0, m = a.length; l < m; l++) {
var o = a[l];
c.push(d.artistLink(o.id).toString());
var k = {};
f.push(k);
if (o.name) k.name = o.name;
if (o.portrait && o.portrait[0]) {
var p =
h.str2hex(o.portrait[0].file_id);
k.image = b.normal + p;
k.images = this.createImageSizes(p)
}
if (o.activity_period) {
for (var o = o.activity_period, p = [], q = 0, s = o.length; q < s; q++) {
var u = o[q],
w = u.start_year || u.decade,
u = u.end_year || u.decade + 9;
isNaN(u) && (u = (new Date).getFullYear());
p.push({
start: w,
end: u
})
}
k.years = p.length ? {
from: p[0].start,
to: p[p.length - 1].end
} : null
}
}
return n
},
"@artist_related_artists_snapshot": function(a, b) {
var c = a.args[0],
d = this.retrieve(c, "parsed.related");
if (d) return this.prepareSnapshot(a, b, d.array, null, d.metadata);
if (d = this.retrieve(c, "raw")) return d = this.parseArtists(d.related), this.store(c, "parsed.related", d), this.prepareSnapshot(a, b, d.array, null, d.metadata);
this.request([c], b, function(b, g, d) {
this.prepareArtist(b, g, d, 0, !0);
b = this.parseArtists(this.retrieve(c, "raw").related);
this.store(c, "parsed.related", b);
return this.prepareSnapshot(a, g, b.array, null, b.metadata)
})
}
})
})();
(function() {
var d = Spotify.Link,
h = Spotify.App.Responder,
f = window.localStorage;
delete f[null];
delete f.plcstate;
delete f["plcstate:"];
new h({
_user: null,
_ready: !1,
_listeners: [],
_empty: function() {},
_incomingReferrer: null,
_referrer: null,
init: function(b, c) {
this.publisher = c.publisher;
this.player = b.player;
this.contextManager = b.contextManager;
var a = typeof c.shouldGetSavedState !== "undefined" ? c.shouldGetSavedState : !0,
g = this.contextPlayer = b.contextPlayer,
d = this.notifyListeners.bind(this);
g.addEvents({
beforePlay: d,
play: this.notifyListeners.bind(this, "play"),
pause: d,
ended: d,
reset: d
});
this.trigger("session_query", [], function(b) {
this._user = "plcstate:" + Spotify.Utils.Base64.encode(b._username);
this._uname = b._username;
a && this._unfreeze();
this._ready = !0;
this.unqueue()
}.bind(this));
window.addEventListener("beforeunload", this._freeze.bind(this))
},
_unfreeze: function() {
var b = f[this._user];
delete f[this._user];
if (!b) return this;
try {
b = JSON.parse(b)
} catch (c) {
return this
}
var a = this.contextPlayer;
a.setShuffle(b.shuffle);
a.setRepeat(b.repeat);
a.setVolume(b.volume);
a = null;
if (b.__group) {
var g = b.__group;
this.contextManager.getGroup(g.id, !0);
g.array.unshift(g.id);
this.trigger("context_group_append", g.array, function() {
this.resolveContextGroup({
args: [0, g.id, g.index, b.track.number - 1, b.position]
}, {
send: this._empty,
fail: this._empty
}, !0, b.__owner)
}.bind(this), this._empty)
} else {
try {
a = d.fromString(b.context.uri)
} catch (i) {}
if (a) {
if (a.type == "temp-playlist" || a.type == "search") b.__owner = b.context.uri = b.track.album.uri, b.index = b.track.number - 1;
this.resolveContext({
args: [0, b.context.uri, b.index, b.position]
}, {
send: this._empty,
fail: this._empty
}, !0, b.__owner)
} else b.track.uri && this.resolveTrack(b.track.uri, {
args: [0, b.track.uri, b.position]
}, {
send: this._empty,
fail: this._empty
}, !0, b.__owner)
}
},
_freeze: function() {
if (this._user) {
var b = this.contextPlayer.getState(!0);
f[this._user] = JSON.stringify(b)
}
},
notifyListeners: function(b) {
var c = this._listeners;
if (!c.length) return null;
for (var c = c.splice(0, c.length), a = {
type: "change",
data: this.contextPlayer.getState()
}, g = 0, d = c.length; g < d; g++) c[g].send(a);
if (b == "play") {
if (this._incomingReferrer == this._referrer) return this;
b = this._referrer = this._incomingReferrer;
this._incomingReferrer = null;
this.publisher.notify("APPLICATION_PLAYBACK_STARTED", {
origin: b
})
}
},
"@player_event_wait": function(b, c) {
this._listeners.push(c.persist())
},
"@event": "player_event_wait",
"@player_query": function(b, c) {
setTimeout(function() {
c.send(this.contextPlayer.getState())
}.bind(this), 500)
},
"@player_set_shuffle": function(b, c) {
this.contextPlayer.setShuffle( !! b.args[1]);
c.send(!0);
this.notifyListeners()
},
"@player_set_repeat": function(b, c) {
this.contextPlayer.setRepeat( !! b.args[1]);
c.send(!0);
this.notifyListeners()
},
"@player_set_volume": function(b, c) {
var a = b.args[1];
if (typeof a != "number") return c.fail("invalid-request", "Volume value must be a number.");
if (this.contextPlayer.getState().volume == a) return c.send(a);
this.contextPlayer.setVolume(a) ? c.send(a) : c.fail("forbidden", "Cannot seek");
this.notifyListeners()
},
"@player_volume_up": function() {
var b = this.contextPlayer,
c = b.getState().volume * 100;
if (c == 100) return this;
b.setVolume((Math.floor(c / 10) * 10 + 10) / 100);
this.notifyListeners()
},
"@player_volume_down": function() {
var b = this.contextPlayer,
c = b.getState().volume * 100;
if (c == 0) return this;
b.setVolume((Math.floor(c / 10) * 10 - 10) / 100);
this.notifyListeners()
},
"@player_play": function(b, c) {
this.contextPlayer.resume();
c.send(!0)
},
"@player_pause": function(b, c) {
this.contextPlayer.pause();
c.send(!0)
},
"@player_seek": function(b, c) {
var a = b.args[1];
if (typeof a != "number") return c.fail("invalid-request", "Seek value must be a number.");
this.contextPlayer.seek(a) ? c.send(a) : c.fail("forbidden", "Cannot seek")
},
setReferrer: function(b) {
return function(c) {
this._incomingReferrer = c.origin;
return b(c.uri)
}.bind(this)
},
resolveTrack: function(b, c, a, g, d, f) {
var h = this.contextManager,
m = h.get(b);
m || (m = h.create(b), m.append(b.toURI()));
m.setOwner(d);
m.setAnonymous(!0);
this.contextPlayer.play(m, {
track: -1,
ms: parseInt(c.args[4], 10) || 0,
reason: f,
pause: g
}, function(b, c) {
b ? (this.player.trigger("INVALID_TRACK_URI", {
params: {
trackUri: c
}
}), a.fail("unplayable", "The track cannot be played.")) : a.send(!0)
}.bind(this))
},
"@player_play_track": function(b, c) {
try {
var a = d.fromString(b.args[1]);
if (a.type !== "track") throw Error();
} catch (g) {
return c.fail("invalid-request", "Not a track URI.")
}
this.trigger("application_get", [b.origin, b.source], this.setReferrer(this.resolveTrack.bind(this, a, b, c, !1)))
},
getAlbumContext: function(b, c, a) {
var g = this.contextManager.get(b.toString(), !0);
if (g.getLength()) return c(g);
var d = this.retrieve(b, "parsed.tracks");
if (d) return g.concat(d), c(g);
this.trigger("album_tracks_snapshot", [b.toString()], function(a) {
g.concat(a.array);
c(g)
}.bind(this), function() {
a("not-found", "Album not found")
})
},
getPlaylistContext: function(b, c, a, g) {
var c = c || {
track: 0
},
d = this.contextManager,
f = d.get(b);
f ? f.resolve(c, function() {
a(f)
}, this._empty) : this.trigger("playlist_tracks_snapshot", [b.toString(), 0, -1], function() {
var g = d.get(b);
g.resolve(c, function() {
a(g)
}, this._empty)
}.bind(this), function() {
g("not-found", "Playlist not found")
})
},
getSearchContext: function(b, c, a) {
var g = this.contextManager,
d = g.get(b);
if (d) return c(d);
this.trigger("search_tracks_snapshot", [b.query, 0, -1], function() {
var a = g.get(b);
c(a)
}.bind(this), function() {
a("not-found", "Search had no results.")
})
},
getUserToplistContext: function(b, c, a) {
var g = this.contextManager.get(b, !0);
if (g.getLength()) return c(g);
if (b.username == "@") b.username = this._uname;
this.trigger("toplist_user_tracks_snapshot", [d.profileLink(b.username).toURI(), 0, -1], function(a) {
g.concat(a.array);
c(g)
}.bind(this), function() {
a("not-found", "No toptracks for user.")
})
},
getArtistToplistContext: function(b, c, a) {
var g = this.contextManager.get(b, !0);
if (g.getLength()) return c(g);
this.trigger("artist_top_tracks_snapshot", [d.artistLink(b.id), 0, -1], function(a) {
g.concat(a.array);
c(g)
}.bind(this), function() {
a("not-found", "No toptracks for artist.")
})
},
"@@get_contexts": function(b, c) {
var a = b.args;
if (!a.length) return c.send({});
for (var g = {
__wait: a.length
}, f = function(a, b, d) {
d || (g[a] = b);
g.__wait--;
if (g.__wait) return this;
delete g.__wait;
c.send(g)
}, h =
0, l = a.length; h < l; h++) {
var m = a[h],
o = f.bind(null, m);
try {
var k = d.fromString(m)
} catch (p) {
o(!0, !0);
continue
}
if (m = this.contextManager.get(k.toString())) o(m);
else
switch (k.type) {
case "album":
this.getAlbumContext(k, o, o);
break;
case "starred":
case "playlist":
this.getPlaylistContext(k, null, o, o);
break;
case "search":
this.getSearchContext(k, o, o);
break;
case "artist-toplist":
this.getArtistToplistContext(k, o, o);
break;
case "user-top-tracks":
case "user-toplist":
this.getUserToplistContext(k, o, o);
break;
default:
o(!0, !0)
}
}
},
playContext: function(b, c, a, g, d) {
if (!d.getLength(!0)) return a.fail("unplayable", "Context has no tracks.");
d.setOwner(c);
b.pause = g;
this.contextPlayer.play(d, b, function(b, c) {
b ? (this.player.trigger("INVALID_TRACK_URI", {
params: {
trackUri: c
}
}), a.fail("unplayable", "The track cannot be played.")) : a.send(!0)
}.bind(this))
},
resolveContext: function(b, c, a, g, f) {
var h = b.args[1],
b = {
context: null,
track: b.args[2],
ms: parseInt(b.args[3], 10) || 0,
reason: f
};
try {
var l = d.fromString(h)
} catch (m) {
return c.fail("invalid-request", "Not a context URI.")
}
a = this.playContext.bind(this, b, g, c, a);
g = c.fail.bind(c);
if (h = this.contextManager.get(l.toString())) return a(h);
switch (l.type) {
case "album":
return this.getAlbumContext(l, a, g);
case "starred":
case "playlist":
return this.getPlaylistContext(l, b, a, g);
case "search":
return this.getSearchContext(l, a, g);
case "artist-toplist":
return this.getArtistToplistContext(l, a, g);
case "user-toplist":
case "user-top-tracks":
return this.getUserToplistContext(l, a, g);
default:
return c.fail("invalid-request", "Not a context.")
}
},
"@player_play_context": function(b, c) {
this.trigger("application_get", [b.origin, b.source], this.setReferrer(this.resolveContext.bind(this, b, c, !1)))
},
resolveContextGroup: function(b, c, a, g) {
var f = this.contextManager,
h = b.args[1],
b = {
context: b.args[2],
track: b.args[3],
ms: parseInt(b.args[4], 10) || 0
};
try {
var l = d.fromString(h)
} catch (m) {
return c.fail("invalid-request", "Not a context URI.")
}
a = this.playContext.bind(this, b, g, c, a);
c.fail.bind(c);
f = f.getGroup(l.toString());
if (!f) return c.fail("invalid-request", "Not a context.");
a(f)
},
"@player_play_context_group": function(b, c) {
this.trigger("application_get", [b.origin, b.source], this.setReferrer(this.resolveContextGroup.bind(this, b, c, !1)))
},
"@@player_play_toggle": function(b, c) {
this.contextPlayer.togglePlay();
return c.send(!0)
},
"@player_skip_to_next": function(b, c) {
this.contextPlayer.next(null, function(a) {
a ? c.fail("forbidden", "Action not allowed") : c.send(!0)
})
},
"@player_skip_to_prev": function(b, c) {
this.contextPlayer.previous(null, function(a) {
a ? c.fail("forbidden", "Action not allowed") : c.send(!0)
})
},
"@context_group_create": function(b, c) {
var a = b.args[0];
this.trigger("application_get_uri", [b.origin, b.source], function(b) {
b = d.fromString(b).id;
b = d.contextGroupLink(b, a).toString();
this.contextManager.getGroup(b, !0);
c.send({
uri: b
})
}.bind(this))
},
"@context_group_snapshot": function(b, c) {
var a = b.args,
g = this.contextManager.getGroup(a[0]);
if (!g) return c.fail("not-found", "Context group does not exist.");
for (var a = this.createDimensions(a[1], a[2]), d = g.slice(a.start, a.start + a.length), f = d.length; f--;) d[f] = d[f].getId();
g = {
range: {
offset: a.start,
length: d.length
},
length: g.unwrap().getContextsLength(),
array: d
};
return c.send(g)
},
"@context_group_append": function(b, c) {
var a = this.contextManager.getGroup(b.args[0]);
if (!a) return c.fail("not-found", "Context group does not exist.");
var g = b.args.slice(1);
this.trigger("get_contexts", g, function(b) {
for (var d = [], f = 0, h = g.length; f < h; f++) {
var o = b[g[f]];
o && d.push(o)
}
a.concat(d);
c.send(a.unwrap().getContextsLength() - d.length)
}, function() {
c.fail("transient", "Cannot perform operation.")
})
},
"@context_group_insert": function(b, c) {
var a = b.args,
g = this.contextManager.getGroup(a[0]);
if (!g) return c.fail("not-found", "Context group does not exist.");
var d = b.args[1],
f = a[3];
this.trigger("get_contexts", [f, a[1]], function(a) {
f = a[f];
d = a[f];
if (!f || !d) return c.fail("forbidden", "Cannot perform operation.");
if (g.insert(d, f, d)) return c.send(!0)
}, function() {
c.fail("transient", "Cannot perform operation.")
})
},
"@context_group_remove": function(b, c) {
var a = b.args[1],
g = b.args[2],
d = this.contextManager.getGroup(b.args[0]);
if (!d) return c.fail("not-found", "Context group does not exist.");
this.trigger("get_contexts", [g], function(b) {
g = b[g];
if (!g) return c.fail("not-found", "No such context.");
if (d.remove(a, g)) return c.send(!0)
}, function() {
c.fail("transient", "Cannot perform operation.")
})
},
"@context_group_trim": function() {},
"@context_group_clear": function(b, c) {
var a = this.contextManager.getGroup(b.args[0]);
if (a) return a.clear(), c.send(!0);
c.fail("not-found", "Context group does not exist.")
},
"@@play_context": function(b, c) {
this.resolveContext(b, c, !1, b.origin, b.args[4])
},
"@@play_track": function(b, c) {
var a = b.args[2];
try {
var g = d.fromString(b.args[1]);
if (g.type !== "track") throw Error();
} catch (f) {
return c.fail("invalid-request", "Not a track URI.")
}
this.resolveTrack(g, b, c, !1, b.origin, a)
},
end: !0
})
})();
(function() {
var d = Spotify.Utils,
h = Spotify.Link,
f = Spotify.App.SourceURLs;
new Spotify.App.Responder({
_ready: !1,
_user: null,
_starredFailed: !1,
_starredTries: 1,
_starredContext: null,
_starredMap: {},
_rootFailed: !1,
_rootTries: 1,
_lists: [],
_subscribed: {},
_requestBuffer: new Spotify.App.RequestBuffer,
_requestedTracks: {},
_requestedMeta: {},
_requestedPublished: {},
_listeners: {},
init: function(b) {
this.contextManager = b.contextManager;
this.use({
service: b.playlist,
popcount: b.popcount
})
},
start: function() {
this.trigger("session_query", [], function(b) {
var a;
a = this._user = b._username, b = a;
this._userURI = h.profileLink(b).toURI();
this._userStarred = h.starredLink(b).toURI();
this.fetchStarred();
this.fetchRoot()
}.bind(this))
},
prepareMap: function() {
for (var b = this._lists, c = this._subscribed, a = b.length; a--;) {
var g = b[a];
g && g.type != "empty" && (c[g] = !0)
}
this._ready = !0;
this.unqueue()
},
parseRoot: function(b) {
this._rootFailed = !1;
if (b.length == 0) return this.prepareMap();
var c = b.contents.length;
this._lists = this._lists.concat(b.contents);
return c == 200 ? this.fetchRoot() : this.prepareMap()
},
fetchRoot: function() {
this.service.rootlist({
username: this._user,
offset: this._lists.length,
total: 200
}, this.parseRoot.bind(this), function(b) {
b.code == 404 ? (this._rootFailed = !1, this.prepareMap()) : this._rootFailed = !0;
this._ready = !0;
this.unqueue()
}.bind(this))
},
parseStarred: function(b) {
this._starredFailed = !1;
for (var c = this._starredMap, a = [], g = b.contents, d = 0, f = g.length; d < f; d++) {
var l = g[d],
l = l.type == "empty" ? "spotify:empty" : l.toURI();
c[l] = !0;
a.push(l)
}
c = this.contextManager.get(h.starredLink(this._user));
c.splice(c.getLength(), a);
if (c.getLength() != b.length) return this.fetchStarred()
},
fetchStarred: function() {
this.service.starredPlaylist({
username: this._user,
offset: this.contextManager.get(h.starredLink(this._user), !0).getLength(),
total: 200
}, this.parseStarred.bind(this), function() {
this._starredFailed = !0
}.bind(this))
},
notifyListeners: function(b, c, a, g) {
var d;
b != this._user ? (typeof b == "string" && (b = h.fromString(b)), d = b.type == "starred" && b.username == this._user ? [b.toString(), "spotify:starred", "spotify:user:@:starred"] : [b.toString()]) : d = [b];
if (c == "remove" && "index" in a) for (var f = a.indices = [], b = 0, l = a.length; b < l; b++) f.push(a.index + b);
for (f = d.length; f--;) {
b = d[f];
b = this._listeners[b];
l = {
type: c,
data: a,
uris: a.array || [],
receiver: g || null
};
if (a.index) l.index = a.index;
if (a.indices) l.indices = a.indices;
if (b && b.length != 0) for (var b = b.splice(0, b.length), m = 0, o = b.length; m < o; m++) b[m].send(l)
}
return this
},
"@library_event_wait": function(b, c) {
(this._listeners[this._user] || (this._listeners[this._user] = [])).push(c.persist())
},
"@starred_event_wait": function(b, c) {
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a = h.starredLink(this._user);
else
try {
if (a = h.fromString(a), a.type != "starred") throw Error();
} catch (d) {
return c.fail("invalid-uri", "Not a valid starred playlist.")
}(this._listeners[a] || (this._listeners[a] = [])).push(c.persist())
},
"@playlist_event_wait": function(b, c) {
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a = h.starredLink(this._user);
else
try {
a = h.fromString(a)
} catch (d) {
return c.fail("invalid-uri", "Not a valid playlist.")
}(this._listeners[a] || (this._listeners[a] = [])).push(c.persist())
},
resolveURI: function(b, c) {
var b = encodeURIComponent(b),
a = c.match(/^https?:\/\/([A-Za-z0-9_-]+).*/),
a = a ? a[1] : "";
return h.temporaryPlaylistLink(a, b).toString()
},
flushRequests: function() {
var b = this._requestBuffer.takeIds();
if (b.length) for (var c = 0, a = b.length; c < a; c++) {
var d = b[c];
this.service.metadata(d, this.format.bind(this, d), this.handleMetadataError.bind(this, d))
}
},
format: function(b, c) {
var a = this._requestBuffer,
b =
h.fromString(b);
if (!c.uri) c.uri = b.toURI();
var d = this.parse(b, c);
this.attachPermissions(b, d);
this.store(b, "parsed.metadata", d);
d.subscribed = b in this._subscribed;
for (var a = a.takeReplies(b), f = a.length; f--;) {
var n = a[f];
n.buildMosaic ? this.trigger("playlist_tracks_snapshot", [b.toString(), 0, 200], this.buildMosaic.bind(this, b, n), n.send.bind(n, {
image: null
})) : n.send(d)
}
},
handleMetadataError: function(b, c) {
var a = this._requestBuffer,
d, f;
switch (c.code) {
case 404:
d = "not-found";
f = "No metadata found for playlist.";
break;
default:
d = "transient", f = "Possible issues with the playlist service."
}
for (var a = a.takeReplies(b), h = a.length; h--;) a[h].fail(d, f)
},
request: function(b, c, a) {
var d = this._requestedMeta[b] || (this._requestedMeta[b] = []);
if (d.length) return d.push({
reply: c,
payload: a
}), this;
d.push({
reply: c,
payload: a
});
this.service.metadata(b, this.prepare.bind(this, b, d), function(a) {
var c;
switch (a.code) {
case 404:
a = "not-found";
c = "No metadata found for playlist.";
break;
default:
a = "transient", c = "Possible issues with the playlist service."
}
for (var f =
d.splice(0, d.length), h = f.length; h--;) {
var o = f[h];
o.payload[b] = {
error: a,
message: c
};
o.payload._count--;
if (!o.payload._count) {
var k = o.payload;
this._userStarred in k && (k[null] = k["spotify:starred"] = k["spotify:user:@:starred"] = k[this._userStarred]);
o.reply.send(o.payload)
}
}
}.bind(this))
},
prepare: function(b, c, a) {
b = h.fromString(b);
if (!a.uri) a.uri = b.toURI();
a = this.parse(b, a);
this.attachPermissions(b, a);
this.store(b, "parsed.metadata", a);
a.subscribed = b in this._subscribed;
for (var c = c.splice(0, c.length), d = c.length; d--;) {
var f =
c[d],
n = f.reply,
f = f.payload;
n.buildMosaic ? this.trigger("playlist_tracks_snapshot", [b.toString(), 0, 200], this.buildMosaic.bind(this, b, n, f), this.buildMosaicError.bind(this, b, n, f)) : (f[b] = a, f._count--)
}
f._count || (this._userStarred in f && (f[null] = f["spotify:starred"] = f["spotify:user:@:starred"] = f[this._userStarred]), n.send(f))
},
parse: function(b, c) {
var a = {
uri: c.uri,
name: b.type == "starred" ? "Starred" : c.name,
owner: {
uri: h.profileLink(c.owner).toString()
},
collaborative: !! c.collaborative,
description: c.description || ""
};
if (c.picture) {
var g = c.picture;
try {
g = decodeURIComponent(g)
} catch (i) {}
g = d.str2hex(g);
a.image = f.normal + g;
a.images = this.createImageSizes(g)
}
return a
},
attachPermissions: function(b, c) {
typeof b == "string" && (b = h.fromString(b));
var a = {
"delete": !1,
editDescription: !1,
insertTracks: !1,
removeTracks: !1,
rename: !1
};
if (c.owner && c.owner.uri == this._userURI) a["delete"] = !0, a.editDescription = !0, a.insertTracks = !0, a.removeTracks = !0, a.rename = !0;
if (c.collaborative) a.insertTracks = !0, a.removeTracks = !0;
switch (b.type) {
case "user-toplist":
case "user-top-tracks":
case "starred":
a["delete"] = !1, a.editDescription = !1, a.rename = !1
}
c.allows = a;
return this
},
"@playlist_metadata": function(b, c) {
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a = h.starredLink(this._user);
else
try {
a = h.fromString(a)
} catch (d) {
return c.fail("invalid-uri", "Not a valid playlist URI")
}
var f = this._requestBuffer,
n;
switch (a.type) {
case "temp-playlist":
return (n = this.retrieve(a, "parsed.metadata")) || (n = {
error: "not-found",
message: "Temporary playlist does not exist"
}), c.send(n);
case "user-toplist":
case "user-top-tracks":
if (n =
this.retrieve(a, "parsed.metadata")) return n.subscribed = a in this._subscribed, c.send(n);
else f.push(a.toURI(), c), this.format(a.toURI(), {
uri: a.toURI(),
name: "Top tracks",
owner: a.username,
collaborative: !1,
description: ""
});
break;
case "starred":
case "playlist":
if (n = this.retrieve(a, "parsed.metadata")) return n.subscribed = a in this._subscribed, c.send(n);
else f.push(a, c);
break;
default:
return c.fail("not-implemented", "This playlist type is not supported.")
}
},
buildMosaicError: function(b, c, a) {
a[b] = {
image: null
};
a._count--;
if (!a._count) return this._userStarred in a && (a[null] = a["spotify:starred"] = a["spotify:user:@:starred"] = a[this._userStarred]), c.send(a)
},
buildMosaic: function(b, c, a) {
var d = a.array;
if (!d.length) return c.send({
image: null
});
this.trigger("track_multi_metadata", d, function(a) {
for (var h = {}, l = [], m = 0, o = d.length; m < o; m++) {
var k = a[d[m]];
k && k._imgfid && !h[k._imgfid] && (h[k._imgfid] = 1, l.push(k._imgfid))
}
a = "";
a = l.length < 4 ? l[0] : l.slice(0, 4).join("");
l = this.retrieve(b, "parsed.metadata");
l.image = f.normal + a;
l.images =
this.createImageSizes(a, !0);
c.send({
image: l.image,
images: l.images
})
}.bind(this), c.send.bind(c, {
image: null
}))
},
"@playlist_profile": function(b, c) {
c.buildMosaic = !0;
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a = h.starredLink(this._user);
else
try {
a = h.fromString(a)
} catch (d) {
return c.fail("invalid-uri", "Not a valid playlist URI.")
}
var f = this._requestBuffer,
n;
switch (a.type) {
case "temp-playlist":
if (n = this.retrieve(a, "parsed.metadata")) if (n.image) return c.send({
image: n.image,
images: n.images
});
else this.trigger("playlist_tracks_snapshot", [a.toString(), 0, 200], this.buildMosaic.bind(this, a, c), c.send.bind(c, {
image: null
}));
else
return c.fail("not-found", "Temporary playlist does not exist.");
break;
case "user-toplist":
case "user-top-tracks":
if (n = this.retrieve(a, "parsed.metadata")) if (n.image) return c.send({
image: n.image,
images: n.images
});
else this.trigger("playlist_tracks_snapshot", [a.toString(), 0, 200], this.buildMosaic.bind(this, a, c), c.send.bind(c, {
image: null
}));
else this.trigger("playlist_tracks_snapshot", [a.toString(), 0, 200], this.buildMosaic.bind(this, a, c), c.send.bind(c, {
image: null
}));
break;
case "starred":
case "playlist":
if (n = this.retrieve(a, "parsed.metadata")) if (n.image) return c.send({
image: n.image,
images: n.images
});
else this.trigger("playlist_tracks_snapshot", [a.toString(), 0, 200], this.buildMosaic.bind(this, a, c), c.send.bind(c, {
image: null
}));
else f.push(a, c);
break;
default:
return c.fail("not-implemented", "This playlist type is not supported")
}
},
preparePopularity: function(b, c, a) {
a = Math.round(Math.min(Math.log((a[0].count || 0) + 1) / Math.LN10 * 25, 100));
this.store(b, "playlist.popularity", a);
c.send({
popularity: a
})
},
"@playlist_popularity": function(b, c) {
var a = b.args[0],
d, f;
try {
d = h.fromString(a), f = d.type
} catch (n) {}
if (!d || f != "starred" && f != "playlist" && f != "user-toplist" && f != "user-top-tracks") return c.send({
popularity: 0
}), null;
d = this.retrieve(a, "playlist.popularity");
if (d != null) return c.send({
popularity: d
});
this.popcount.get(a, 1, !1, 0, this.preparePopularity.bind(this, a, c), this.handleError.bind(this, c))
},
"@playlist_restricted": function(b, c) {
for (var a = b.args.slice(0), d = a.length, f = {}; d--;) {
var n = a[d];
try {
var l = h.fromString(l),
m = l.type;
if (m != "starred" || m != "playlist" || m != "user-toplist" || m != "user-top-tracks") throw Error();
} catch (o) {
f[n] = {
error: "invalid-uri",
message: "Not a valid playlist URI."
};
continue
}
f[n] = {
ownedByCurrentUser: !! (l.username == "@" || l.username == this._user)
}
}
return c.send(f)
},
"@playlist_create": function(b, c) {
var a = this._lists;
this.service.createPlaylist(b.args[0] || "New playlist", function(b) {
a.unshift(h.fromString(b));
c.send({
uri: b
});
this.notifyListeners(this._user, "insert", {
index: 0,
length: 1,
array: [b]
}, "playlists")
}.bind(this), this.handleError.bind(this, c))
},
"@playlist_create_temporary": function(b, c) {
var a = this.resolveURI(b.args[0], b.origin);
this.contextManager.get(a, !0);
var d = {
uri: a,
name: b.args[0],
owner: "",
collaborative: !1,
description: "",
image: null,
subscribed: !1
};
this.attachPermissions(a, d);
this.store(a, "parsed.metadata", d);
return c.send(d)
},
"@playlist_remove_temporary": function(b, c) {
var a = this.resolveURI(b.args[0], b.origin);
this.contextManager.remove(a);
this.store(a, "parsed.metadata", null);
return c.send(!0)
},
handleError: function(b, c) {
var a, d;
switch (c.code) {
case 404:
a = "not-found";
d = "No playlist found for URI.";
break;
case 401:
a = "forbidden";
d = "Not allowed.";
break;
default:
a = "transient", d = "Possible issues with the playlist service."
}
return b.fail(a, d)
},
list: function(b, c, a, d, f) {
for (var h = this._requestedTracks, h = h[b] || (h[b] = []), l = {
reply: f,
offset: c,
length: d
}, m, o, k = h.length; k--;) if (m = h[k], !(m.start > c && m.end < a)) {
o = m.replies;
o.push(l);
if (!m.done) return this;
m.done = !1;
break
}
o || (o = [l], m = {
done: !1,
start: c,
end: c + 199,
replies: o
}, h.push(m));
m.done || this.service.list({
uri: b,
offset: c,
total: 200
}, this.prepareTracks.bind(this, b, c, d, m), this.handleError.bind(this, f))
},
prepareTracks: function(b, c, a, d, f) {
d.done = !0;
for (var a = d.replies.splice(0, d.replies.length), d = [], h = 0, l = f.contents.length; h < l; h++) {
var m = f.contents[h];
m.type == "empty" ? d.push("spotify:empty") : d.push(m.toString())
}
b = this.contextManager.get(b, !0);
b.splice(c, d);
b.setFullLength(f.length);
b.setLoader(this.fillContext.bind(this));
c = 0;
for (d = a.length; c < d; c++) h = a[c], l = {
range: {
offset: h.offset,
length: h.length
},
length: f.length,
array: b.slice(h.offset, h.offset + h.length)
}, h.reply.send(l)
},
fillContext: function(b, c, a) {
var a = a ||
function() {},
d = this,
f = b.getLength(),
h = b.getFullLength();
if (f >= h) return a();
this.trigger("playlist_tracks_snapshot", [b.getId(), f, -1], function() {
d.fillContext(b, c, a)
})
},
"@playlist_subscribers_snapshot": function(b, c) {
var a = b.args[0],
d = b.args[1] || 0,
f = b.args[2],
f = f == -1 ? 500 : Math.min(f, 500),
h = d + f;
this.popcount.get(a, h, !1, null, this.prepareSubscribers.bind(this, a, c, d, f, h), this.handleError.bind(this, c))
},
prepareSubscribers: function(b, c, a, d, f, n) {
b = [];
if (n[0].user) for (var l = 0, m = n[0].user.length; l < m; l++) b.push(h.profileLink(n[0].user[l]).toURI());
a = {
range: {
offset: a,
length: d
},
length: n[0].count,
array: b.slice(a, f)
};
return c.send(a)
},
"@playlist_tracks_snapshot": function(b, c) {
var a = b.args[0],
a = a == null || a == "spotify:starred" || a == "spotify:user:@:starred" ? h.starredLink(this._user) : h.fromString(b.args[0]);
if (a.type == "user-toplist" || a.type == "user-top-tracks") return this.trigger("toplist_user_tracks_snapshot", b.args, c.send.bind(c), c.fail.bind(c));
var d = b.args[1] || 0,
f = b.args[2],
f = f == -1 ? 200 : Math.min(f, 200),
n = d + f,
l = this.contextManager.get(a);
if (l) {
var m = l.getFullLength(),
o = Math.min(n, m || Infinity);
if (l.hasRange(d, o)) return a = {
range: {
offset: d,
length: f
},
length: m,
array: l.slice(d, n)
}, c.send(a);
else if (a.type == "temp-playlist") return a = {
range: {
offset: d,
length: l.getLength()
},
length: m,
array: l.slice(d)
}, c.send(a)
}
this.list(a.toURI(), d, n, f, c)
},
tracksAppended: function(b, c, a) {
var d = this.contextManager.get(b, !0);
this.trigger("playlist_tracks_snapshot", [b.toURI(), 0, 1], function(f) {
d.splice(d.getFullLength(), 0, c);
a.send(!0);
this.notifyListeners(b, "insert", {
index: f.length,
length: c.length,
array: c
})
}.bind(this), a.send.bind(a, !0))
},
"@playlist_tracks_append": function(b, c) {
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a = h.starredLink(this._user);
else
try {
a = h.fromString(b.args[0])
} catch (d) {
return c.fail("invalid-uri", "Not a valid Spotify URI.")
}
var f = b.args.slice(1);
switch (a.type) {
case "temp-playlist":
var n = this.contextManager.get(a);
if (!n) return c.fail("not-found", "The playlist was not found.");
var l = n.getLength();
n.concat(f);
c.send(!0);
this.notifyListeners(a, "insert", {
index: l,
length: f.length,
array: f
});
break;
case "playlist":
this.service.addTracksInPlaylist(a.toURI(), f, this.tracksAppended.bind(this, a, f, c), this.handleError.bind(this, c));
break;
case "starred":
return this.trigger("starred_tracks_append", b.args, c.send.bind(c), c.fail.bind(c));
default:
return c.fail("invalid-uri", "Not a valid Spotify playlist URI.")
}
},
removeLocal: function(b, c, a, d) {
if (!this.contextManager.get(b).remove(c, a)) return d.fail("invalid-request", "Cannot perform operation.");
this.notifyListeners(b, "remove", {
index: c,
length: 1,
array: [a.toString()]
});
return this.service.removeFromPlaylist(b.toURI(), c, 1, d.send.bind(d, !0), this.handleError.bind(this, d))
},
"@playlist_tracks_remove": function(b, c) {
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a =
h.starredLink(this._user);
else
try {
a = h.fromString(b.args[0])
} catch (d) {
return c.fail("invalid-uri", "Not a valid Spotify URI.")
}
var f = b.args[1],
n = b.args[2],
l = this.contextManager.get(a);
switch (a.type) {
case "temp-playlist":
if (!l) return c.fail("not-found", "The playlist was not found.");
l.remove(f, n) ? (c.send(!0), this.notifyListeners(a, "remove", {
index: f,
length: 1,
array: [n.toString()]
})) : c.fail("invalid-request", "Cannot perform operation.");
break;
case "playlist":
return this.trigger("playlist_tracks_snapshot", [a.toURI(), f, 1], this.removeLocal.bind(this, a, f, n, c), c.send.bind(c));
case "starred":
return this.trigger("starred_tracks_remove", b.args, c.send.bind(c), c.fail.bind(c));
default:
return c.fail("invalid-uri", "Not a valid Spotify playlist URI.")
}
},
"@playlist_tracks_insert": function(b, c) {
var a = b.args,
d = this.contextManager.get(a[0]);
if (d && d.insert(a[1], a[2], a.slice(3))) return c.send(!0);
c.fail("not-found", "The playlist was not found.")
},
"@playlist_tracks_trim": function(b, c) {
var a = b.args,
d = this.contextManager.get(a[0]);
if (d && d.trim(a[1], a[2])) return c.send(!0);
c.fail("not-found", "The playlist was not found")
},
"@playlist_tracks_clear": function(b, c) {
var a = this.contextManager.get(b.args[0]);
if (a) return a.clear(), c.send(!0);
c.fail("not-found", "The playlist was not found.")
},
"@playlist_enforce_rules": function(b, c) {
var a = this.contextManager.get(b.args[0]);
return !a ? c.fail("not-found", "Playlist does not exist.") : a.setRule(b.args[1]) ? c.send(!0) : c.fail("forbidden", "Cannot enforce playlist rule")
},
preparePlaylists: function(b, c, a) {
for (var d = [], f = 0, h = a.contents.length; f < h; f++) {
var l = a.contents[f];
switch (l.type) {
case "user-toplist":
case "artist-toplist":
case "toplist":
case "playlist":
case "starred":
case "user-top-tracks":
d.push(l.toString());
break;
default:
d.push("spotify:empty")
}
}
return c.send({
range: {
offset: b[1],
length: d.length
},
length: a.length,
array: d
})
},
rootlist: function(b, c) {
var a = b[1],
d = b[2],
d = d == -1 ? 200 : Math.min(d, 200);
this.preparePlaylists(b, c, {
length: this._lists.length,
contents: this._lists.slice(a, a + d)
})
},
"@library_playlists_snapshot": function(b, c) {
var a = b.args[0];
try {
if (a = h.fromString(a), a.type != "profile") throw Error();
} catch (d) {
return c.fail("invalid-uri", "Not a valid user URI.")
}
if (a.username != "@" && a.username != this._user) return c.fail("forbidden", "Cannot fetch playlists of user not logged into the session.");
this._rootFailed ? setTimeout(this.fetchRoot.bind(this), 10 * this._rootTries++) : this.rootlist(b.args, c)
},
preparePublished: function(b, c, a, d, f) {
d.done = !0;
for (var a = d.replies.splice(0, d.replies.length), d = [], n = 0, l = f.contents.length; n < l; n++) {
var m =
f.contents[n];
switch (m.type) {
case "user-toplist":
case "artist-toplist":
case "toplist":
case "playlist":
case "starred":
case "user-top-tracks":
d.push(m.toString());
break;
default:
d.push("spotify:empty")
}
}
b = this.contextManager.get(h.profileLink(b), !0);
b.splice(c, d);
b.setFullLength(f.length);
c = 0;
for (d = a.length; c < d; c++) n = a[c], l = {
range: {
offset: n.offset,
length: n.length
},
length: f.length,
array: b.slice(n.offset, n.offset + n.length)
}, n.reply.send(l)
},
requestPublished: function(b, c, a, d, f) {
for (var h = this._requestedPublished, h = h[b] || (h[b] = []), l = {
reply: f,
offset: c,
length: d
}, m, o, k = h.length; k--;) if (m = h[k], !(m.start > c && m.end < a)) {
o = m.replies;
o.push(l);
if (!m.done) return this;
m.done = !1;
break
}
o || (o = [l], m = {
done: !1,
start: c,
end: c + 199,
replies: o
}, h.push(m));
m.done || this.service.publishedRootlist({
username: b,
offset: c,
total: 200
}, this.preparePublished.bind(this, b, c, d, m), this.handleError.bind(this, f))
},
"@library_published_snapshot": function(b, c) {
var a = b.args[0];
try {
if (a = h.fromString(a), a.type != "profile") throw Error();
} catch (d) {
return c.fail("invalid-uri", "Not a valid user URI.")
}
if (a.username == "@") a.username = this._user;
var f = b.args[1] || 0,
n = b.args[2],
n = n == -1 ? 200 : Math.min(n, 200),
l = f + n,
m = this.contextManager.get(h.rootlistLink(a.username));
if (m) {
var o = m.getFullLength(),
k = Math.min(l, o || Infinity);
if (m.hasRange(f, k)) return a = {
range: {
offset: f,
length: n
},
length: o,
array: m.slice(f, l)
}, c.send(a);
else if (uri.type == "temp-rootlist") return a = {
range: {
offset: f,
length: m.getLength()
},
length: o,
array: m.slice(f)
}, c.send(a)
}
this.requestPublished(a.username, f, l, n, c)
},
playlistRenamed: function(b, c, a) {
var d = this.retrieve(b, "parsed.metadata");
if (d) d.name = c;
a.send(!0);
this.notifyListeners(b, "change", {
name: c
})
},
"@playlist_set_name": function(b, c) {
try {
var a = h.fromString(b.args[0])
} catch (d) {
return c.fail("invalid-uri", "Not a valid Spotify URI.")
}
var f = b.args[1] || "New playlist";
switch (a.type) {
case "temp-playlist":
var n = this.retrieve(a, "parsed.metadata");
if (!n) return c.fail("not-found", "Playlist not found.");
n.name = f;
c.send(!0);
this.notifyListeners(a, "change", {
name: f
});
break;
case "playlist":
return this.service.renamePlaylist(a.toURI(), f, this.playlistRenamed.bind(this, a, f, c), this.handleError.bind(this, c));
default:
return c.fail("invalid-uri", "Not a valid Spotify playlist URI.")
}
},
"@@starred_tracks_decorate": function(b, c) {
var a = b.args[0],
d;
for (d in a) if (a[d]) a[d].starred = this._starredFailed ? !1 : d in this._starredMap;
return c.send(a)
},
"@@starred_track_decorate": function(b, c) {
var a = b.args[0],
d = b.args[1];
d.starred = this._starredFailed ? !1 : a in this._starredMap;
return c.send(d)
},
"@starred_request": function(b, c) {
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a = h.starredLink(this._user);
else
try {
a = h.fromString(a);
if (a.type != "profile") throw Error();
a = h.starredLink(a.username)
} catch (d) {
return c.fail("invalid-uri", "Not a valid user URI.")
}
c.send({
uri: a.toURI()
})
},
"@starred_tracks_snapshot": function(b, c) {
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a = h.starredLink(this._user);
else
try {
if (a = h.fromString(a), a.type != "starred") throw Error();
} catch (d) {
return c.fail("invalid-uri", "Not a valid starred list URI.")
}
b.args[0] = a.toURI();
this.trigger("playlist_tracks_snapshot", b.args, c.send.bind(c), c.fail.bind(c))
},
starredTracksAppended: function(b, c, a) {
var d = this._starredMap,
f = this.contextManager.get(b),
h = f.getLength();
f.concat(c);
for (f = c.length; f--;) d[c[f]] = !0;
a.send(!0);
this.notifyListeners(b, "insert", {
index: h,
length: c.length,
array: c
})
},
"@starred_tracks_append": function(b, c) {
var a = b.args[0];
if (a == null || a == "spotify:starred" || a == "spotify:user:@:starred") a = h.starredLink(this._user);
else {
try {
if (a = h.fromString(a), a.type != "starred") throw Error();
} catch (d) {
return c.fail("invalid-uri", "Not a valid starred list URI.")
}
if (a.username != this._user) return c.fail("forbidden", "Cannot add a track to another user's starred tracks")
}
for (var f = this._starredMap, n = [], l = 1, m = b.args.length; l < m; l++) b.args[l] in f || n.push(b.args[l]);
if (!n.length) return c.send(!0);
this.service.starTracks(n, this.starredTracksAppended.bind(this, a, n, c), this.handleError.bind(this, c))
},
"@track_star": function(b, c) {
var a = b.args[0];
try {
if (a = h.fromString(a), a.type != "track") throw Error();
} catch (d) {
return c.fail("invalid-uri", "Not a valid track URI.")
}
this.trigger("starred_tracks_append", [null, a.toURI()], c.send.bind(c), c.fail.bind(c))
},
"@library_star": function(b, c) {
b.args.shift();
this.trigger("track_star", b, c.send.bind(c), c.fail.bind(c))
},
starredTracksRemoved: function(b, c, a, d) {
d.send(!0);
this.notifyListeners(b, "remove", {
index: a,
length: 1,
array: [c]
})
},
"@starred_tracks_remove": function(b, c) {
var a = this._starredMap,
d = b.args[0],
f = b.args[1],
n = b.args[2];
if (d == null || d == "spotify:starred" || d == "spotify:user:@:starred") d = h.starredLink(this._user);
else {
try {
if (d = h.fromString(d), d.type != "starred") throw Error();
} catch (l) {
return c.fail("invalid-uri", "Not a valid starred list URI.")
}
if (d.username != this._user) return c.fail("forbidden", "Cannot remove a track from another user's starred tracks")
}
if (!(n in a)) return c.send(!0);
var m = this.contextManager.get(d);
f == -1 && (f = m.indexOf(n));
if (f == -1 || !m.remove(f, n)) return c.fail("invalid-request", "Cannot perform operation.");
delete a[n];
this.service.unstarTracks([n], this.starredTracksRemoved.bind(this, d, n, f, c), c.send.bind(c, !0))
},
"@track_unstar": function(b, c) {
var a = b.args[0];
try {
if (a = h.fromString(a), a.type != "track") throw Error();
} catch (d) {
return c.fail("invalid-uri", "Not a valid track URI.")
}
this.trigger("starred_tracks_remove", [null, -1, a.toURI()], c.send.bind(c), c.fail.bind(c))
},
"@library_unstar": function(b, c) {
b.args.shift();
this.trigger("track_unstar", b, c.send.bind(c), c.fail.bind(c))
},
subscribePlaylists: function(b, c, a) {
for (var d = this._lists, f = this._subscribed, h = [], l = c.length; l--;) h[l] = c[l].toURI();
this.service.subscribe({
username: b,
uri: h
}, function() {
d.splice.apply(d, [0, 0].concat(c));
for (var b = c.length; b--;) f[c[b]] = !0;
a.send(!0);
this.notifyListeners(this._user, "insert", {
index: 0,
length: c.length,
array: h
}, "playlists")
}.bind(this), this.handleError.bind(this, a))
},
"@library_subscribe": function(b, c) {
var a = h.fromString(b.args[0]);
if (a.username == "@") a.username = this._user;
for (var d = b.args.slice(1), f = [], n = 0, l = d.length; n < l; n++) {
try {
var m = h.fromString(d[n]);
if (m.username == "@") m.username = this._user
} catch (o) {
continue
}
switch (m.type) {
case "user-toplist":
case "user-top-tracks":
case "starred":
case "playlist":
f.push(m)
}
}
f && this.subscribePlaylists(a.username, f, c)
},
unsubscribePlaylists: function(b, c, a) {
for (var d = this._lists, b = h.rootlistLink(b).toURI(), f = c.length, n = []; f--;) {
for (var l = c[f].toString(), m = -1, o = d.length; o--;) if (d[o].toString() === l) {
m = o;
break
}
m != -1 && n.push(m)
}
if (!n.length) return a.send(!0);
for (f = o = n.length; o--;) this.service.removeFromPlaylist(b, n[o], 1, function(b) {
b = d.splice(b, 1).pop();
delete this._subscribed[b];
f--;
f || a.send(!0);
this.notifyListeners(this._user, "remove", {
index: f,
length: 1,
array: [b.toString()]
}, "playlists")
}.bind(this, n[o]), function() {
f--;
f || a.fail("transient", "Something went wrong.")
})
},
"@library_unsubscribe": function(b, c) {
var a = h.fromString(b.args[0]);
if (a.username == "@") a.username = this._user;
for (var d = b.args.slice(1), f = [], n = 0, l = d.length; n < l; n++) {
try {
var m = h.fromString(d[n]);
if (m.username == "@") m.username = this._user
} catch (o) {
continue
}
switch (m.type) {
case "user-toplist":
case "user-top-tracks":
case "starred":
case "playlist":
f.push(m)
}
}
f && this.unsubscribePlaylists(a.username, f, c)
},
"@user_subscribe_playlist": function(b, c) {
var a = this._lists,
d = this._subscribed,
f = h.fromString(b.args[0]).username,
n = h.fromString(b.args[1]);
this.service.subscribe({
username: f,
uri: n.toURI()
}, function() {
a.unshift(n);
d[n] = !0;
c.send(!0);
this.notifyListeners(this._user, "insert", {
index: 0,
length: 1,
array: [n.toURI()]
}, "playlists")
}.bind(this), this.handleError.bind(this, c))
},
"@user_unsubscribe_playlist": function(b, c) {
for (var a = this._lists, d = h.rootlistLink(h.fromString(b.args[0]).username), f = h.fromString(b.args[1]), n = f.toString(), l = a.length, m = -1; l--;) a[l].toString() == n && (m = l);
if (m == -1) return c.fail("not-found", "Not subscribed to this playlist.");
this.service.removeFromPlaylist(d.toString(), m, 1, function() {
a.splice(m, 1);
delete this._subscribed[f];
c.send(!0);
this.notifyListeners(this._user, "remove", {
index: l,
length: 1,
array: [f.toURI()]
}, "playlists")
}.bind(this), this.handleError.bind(this, c))
}
})
})();
(function() {
var d = Spotify.Link;
new Spotify.App.Responder({
_ready: !1,
_listeners: [],
_events: new Spotify.Events,
init: function(d) {
var a;
a = this.service = d.socialGraph, d = a;
d.bind(this._events.RELATIONS_SUBSCRIBE, this.modifyRelations, this, 0);
d.onReady(this.start, this)
},
start: function() {
this._ready = !0;
this.unqueue();
this.service.preloadCurrentUserSubscriptions()
},
modifyRelations: function(h) {
for (var f = h.type === this._events.RELATIONS_SUBSCRIBE ? "add" : "remove", h = h.params.users, b = [], c = 0, a = h.length; c < a; c++) b.push(d.profileLink(h[c]).toString());
this.notifyListeners(f, b)
},
request: function(h, f, b) {
var c = f.args,
a = f.args[0] ? d.fromString(c[0]).username : null,
g = f.args[1],
f = f.args[2];
a === "@" && (a = null);
this.service[h](a, f, g, this.reply.bind(this, b, c), this.handleError.bind(this, b))
},
modify: function(h, f, b) {
for (var f = f.args, c = [], a = 0, g = f.length; a < g; a++) {
var i = d.fromString(f[a]).username;
i !== "@" && c.push(i)
}
this.service[h](c, this.modifyReply.bind(this, b, f), this.handleError.bind(this, b))
},
reply: function(h, f, b) {
var c = [],
a = b[0].users,
b = b[0].length;
if (a) for (var g =
0, i = a.length; g < i; g++) c.push(d.profileLink(a[g].username).toString());
f = this.createSnapshot(f, c, b);
h.send(f)
},
modifyReply: function(d) {
d.send({})
},
handleError: function(d, f) {
var b, c;
switch (f.code) {
case 404:
b = "not-found";
c = "No relation found.";
break;
default:
b = "transient", c = "Possible issues with the socialgraph service."
}
return d.fail(b, c)
},
notifyListeners: function(d, f) {
for (var b = this._listeners.splice(0, this._listeners.length), c = {
type: d,
uris: f,
receiver: "subscriptions"
}, a = 0, g = b.length; a < g; a++) b[a].send(c);
return this
},
"@relations_event_wait": function(d, f) {
this._listeners.push(f.persist())
},
"@relations_subscribers_users_snapshot": function(d, f) {
this.request("getSubscribers", d, f)
},
"@relations_subscriptions_users_snapshot": function(d, f) {
this.request("getSubscriptions", d, f)
},
"@relations_blocked_users_snapshot": function(d, f) {
this.request("getBlocked", d, f)
},
"@relations_dismissed_users_snapshot": function(d, f) {
this.request("getDismissed", d, f)
},
"@relations_hidden_users_snapshot": function(d, f) {
this.request("getHidden", d, f)
},
"@relations_subscribe": function(d, f) {
this.modify("subscribeTo", d, f)
}
})
})();
(function() {
var d = Spotify.App.Responder;
new d({
_ready: !1,
init: function(d, f) {
this.getAppUrl = f.getAppUrl;
this.start()
},
start: function() {
this._ready = !0;
this.unqueue()
},
"@core_request_lookup": function(h, f) {
f.send(d.respondsTo(h.args[0]))
},
"@application_require": function(d, f) {
f.send("http://origin.spapps.keeto.d.spotify.net/" + d.args[0] + "/")
}
})
})();
(function() {
var d = Spotify.Utils.isArray,
h = Spotify.Link,
f = Spotify.App.SourceURLs;
new Spotify.App.Responder({
_ready: !1,
_requested: {},
_fuzzy: {},
create: function() {
this.prepareAlbums = this.prepare.bind(this, this.parseAlbums);
this.prepareArtists = this.prepare.bind(this, this.parseArtists);
this.prepareTracks = this.prepare.bind(this, this.parseTracks);
this.preparePlaylists = this.prepare.bind(this, this.parsePlaylists)
},
init: function(b) {
this.contextManager = b.contextManager;
(this.service = b.search).onReady(this.start, this)
},
start: function() {
this._ready = !0;
this.unqueue()
},
processReplies: function(b, c, a) {
if (a.didYouMean) this._fuzzy[b] = a.didYouMean;
for (b = c.length; b--;) {
var d = c[b];
d.parser.call(this, d.args, d.reply, a)
}
},
processFailures: function(b, c) {
for (var a = c.length; a--;) c[a].reply.fail("transient", "Possible problems with the search service.")
},
request: function(b) {
delete this._requested[b.key];
this.service.search(b.query, {
type: b.type,
offset: b.offset,
total: b.length
}, this.processReplies.bind(this, b.key, b.replies), this.processFailures.bind(this, b.key, b.replies))
},
search: function(b, c, a, d) {
var f = c[0];
if (!f) return a.fail("invalid-request", "Invalid query params.");
var h = c[1],
l = c[2],
l = l == -1 ? 50 : Math.min(l, 50),
m = [f, h, l].join(":"),
c = {
reply: a,
parser: d,
args: c
};
(a = this._requested[m]) ? (a.type |= b, a.replies.push(c)) : (a = this._requested[m] = {
key: m,
query: f,
offset: h,
length: l,
type: b,
replies: [c]
}, setTimeout(this.request.bind(this, a), 10))
},
cache: function(b, c) {
this._cache[b] = {
timestamp: (new Date).getTime(),
value: c
};
return this
},
retrieve: function(b) {
var c = this._cache[b];
if (!c) return null;
return (new Date).getTime() - c.timestamp >= CACHE_TIME ? (delete this._cache[b], null) : c
},
prepare: function(b, c, a, d) {
b = b.call(this, d, c);
if (b == null) return a.fail("transient", "No valid search results found.");
b = this.createSnapshot([null, 0, c[2]], b.array, b.total, b.metadata);
b.range = {
offset: c[1],
length: b.array.length
};
a.send(b)
},
"@search_albums_snapshot": function(b, c) {
this.search(this.service.ALBUMS, b.args, c, this.prepareAlbums)
},
parseAlbums: function(b) {
var c = b.total.albums,
b = b.albums,
a = [],
g = [];
if (b) {
d(b) || (b = [b]);
for (var i = 0, n = b.length; i < n; i++) {
var l = b[i];
if (l.id) {
a.push(h.albumLink(l.id).toURI());
for (var m = {
name: l.name,
type: (l.type || "").toLowerCase(),
popularity: l.popularity,
playable: l.playable,
image: null
}, o = m.artists = [], k = 0, p = l.artists.length; k < p; ++k) o.push({
uri: h.artistLink(l.artists[k].id).toURI(),
name: l.artists[k].name
});
g.push(m);
if (l.cover && l.cover[0]) l = l.cover[0].file_id, m.image = f.normal + l, m.images = this.createImageSizes(l)
}
}
}
return {
total: c,
array: a,
metadata: g
}
},
"@search_artists_snapshot": function(b, c) {
this.search(this.service.ARTISTS, b.args, c, this.prepareArtists)
},
parseArtists: function(b) {
var c = b.total.artists,
b = b.artists,
a = [],
g = [];
if (b) {
d(b) || (b = [b]);
for (var i = 0, n = b.length; i < n; i++) {
var l = b[i];
if (l.id) {
a.push(h.artistLink(l.id).toURI());
var m = {
name: d(l.name) ? l.name.join(", ") : l.name,
popularity: l.popularity,
playable: l.playable,
image: null
};
if (l.portrait && l.portrait[0]) l = l.portrait[0].file_id, m.image = f.normal + l, m.images = this.createImageSizes(l);
g.push(m)
}
}
}
return {
total: c,
array: a,
metadata: g
}
},
"@search_tracks_snapshot": function(b, c) {
var a = b.args,
d = this.contextManager.get(h.searchLink(a[0]));
if (d) {
var f = d.getFullLength(),
a = this.createDimensions(a[1], a[2], 50),
n = Math.min(a.end, f || Infinity);
if (d.hasRange(a.start, n)) return d = {
range: {
offset: a.start,
length: n
},
length: f,
array: d.slice(a.start, n + 1),
metadata: d._context.__meta.slice(a.start, n + 1)
}, c.send(d)
}
this.search(this.service.TRACKS, b.args, c, this.prepareTracks)
},
parseTracks: function(b, c) {
var a = b.total.tracks,
g = b.tracks,
i = [],
n = [];
if (g) {
d(g) || (g = [g]);
for (var l = 0, m = g.length; l < m; l++) {
var o =
g[l];
if (o.id) {
i.push(h.trackLink(o.id).toURI());
for (var k = {
starred: !1,
name: o.name,
album: {
uri: h.albumLink(o.album.id).toURI(),
name: o.album.name,
image: null,
artists: [{
uri: h.artistLink(o.album.artist.id).toURI(),
name: d(o.album.artist.name) ? o.album.artist.name.join(", ") : o.album.artist.name
}]
},
duration: o.length,
playable: o.playable,
popularity: o.popularity,
image: null,
year: o.year
}, p = k.artists = [], q = 0, s = o.artists.length; q < s; ++q) p.push({
uri: h.artistLink(o.artists[q].id).toURI(),
name: o.artists[q].name
});
if (o.album.cover && o.album.cover[0]) o = o.album.cover[0].file_id, k.image = k.album.image = f.normal + o, k.images = k.album.images = this.createImageSizes(o);
n.push(k)
}
}
g = this.contextManager.get(h.searchLink(c[0]), !0, 36E5);
g.setLoader(this.fillContext.bind(this));
g.splice(c[1], i);
g.setFullLength(a);
g = g._context.__meta || (g._context.__meta = []);
g.splice.apply(g, [c[1], 0].concat(n))
}
return {
total: a,
array: i,
metadata: n
}
},
"@search_playlists_snapshot": function(b, c) {
this.search(this.service.PLAYLISTS, b.args, c, this.preparePlaylists)
},
parsePlaylists: function(b) {
var c =
b.total.playlists,
b = b.playlists,
a = [],
g = [];
if (b) {
d(b) || (b = [b]);
for (var h = 0, n = b.length; h < n; h++) {
var l = b[h];
a.push(l.uri);
var m = {
image: null,
name: l.name,
uri: l.uri
},
l = l["image-large"] || l.image || null;
if (typeof l === "string") l = l.split(":").splice(2, l.length - 1).join(""), m.image = f.normal + l, m.images = this.createImageSizes(l);
g.push(m)
}
}
return {
total: c,
array: a,
metadata: g
}
},
fillContext: function(b, c, a) {
var a = a ||
function() {},
d = this,
f = b.getLength();
if (f > c + 20) return a();
try {
var n = h.fromString(b.getId()).query
} catch (l) {
return a()
}
this.trigger("search_tracks_snapshot", [n, f, -1], function() {
d.fillContext(b, c, a)
})
},
parseFuzzy: function(b, c, a) {
b = this._fuzzy[b] = a.didYouMean;
c.send({
fuzzyMatch: b
})
},
"@search_fuzzy_match": function(b, c) {
var a = b.args[0];
this._fuzzy[a] ? c.send({
fuzzyMatch: this._fuzzy[a] || null
}) : this.service.search(a, {
type: this.service.TRACKS,
offset: 0,
total: 20
}, this.parseFuzzy.bind(this, a, c), function() {
c.send({
fuzzyMatch: null
})
})
}
})
})();
(function() {
var d = Spotify.Link;
new Spotify.App.Responder({
_ready: !1,
create: function() {
this.prepareAlbums = this.prepare.bind(this, this.parseAlbums);
this.prepareArtists = this.prepare.bind(this, this.parseArtists);
this.prepareTracks = this.prepare.bind(this, this.parseTracks);
this.preparePlaylists = this.prepare.bind(this, this.parsePlaylists)
},
init: function(d) {
this.service = d.suggest;
this.service.onReady(this.start, this)
},
start: function() {
this._ready = !0;
this.unqueue()
},
suggest: function(d, f, b) {
var c = d[0];
if (!c) return f.fail("invalid-request", "Invalid query param.");
this.service.suggest(c, b.bind(this, d, f), f.fail.bind(f, "transient", "Possible issues with the suggest service."))
},
prepare: function(d, f, b, c) {
d = d.call(this, c);
if (d == null) return b.fail("transient", "Cannot parse results.");
b.send({
range: {
offset: f[1],
length: d.array.length
},
length: d.total,
array: d.array,
metadata: d.metadata
})
},
"@suggest_albums_snapshot": function(d, f) {
this.suggest(d.args, f, this.prepareAlbums)
},
parseAlbums: function(h) {
var h = h.albums,
f = [],
b = [];
if (h) for (var c = 0, a = h.length; c < a; c++) {
f.push(d.albumLink(h[c].id).toString());
var g = [];
for (j = 0, lj = h[c].artists.length; j < lj; j++) g.push({
uri: d.artistLink(h[c].artists[j].id).toString(),
name: h[c].artists[j].name
});
b.push({
name: h[c].name,
image: Spotify.App.SourceURLs.small + h[c].image,
artists: g,
popularity: h[c].popularity
})
}
return {
total: f.length,
array: f,
metadata: b
}
},
"@suggest_artists_snapshot": function(d, f) {
this.suggest(d.args, f, this.prepareArtists)
},
parseArtists: function(h) {
var h = h.artists,
f = [],
b = [];
if (h) for (var c = 0, a = h.length; c < a; c++) f.push(d.artistLink(h[c].id).toString()), b.push({
name: h[c].name,
image: Spotify.App.SourceURLs.small + h[c].image,
popularity: h[c].popularity
});
return {
total: f.length,
array: f,
metadata: b
}
},
"@suggest_tracks_snapshot": function(d, f) {
this.suggest(d.args, f, this.prepareTracks)
},
parseTracks: function(h) {
var h = h.tracks,
f = [],
b = [];
if (h) for (var c = 0, a = h.length; c < a; c++) {
f.push(d.trackLink(h[c].id).toString());
var g = [];
for (j = 0, lj = h[c].artists.length; j < lj; j++) g.push({
uri: d.artistLink(h[c].artists[j].id).toString(),
name: h[c].artists[j].name
});
b.push({
name: h[c].name,
image: Spotify.App.SourceURLs.small + h[c].image,
artists: g,
popularity: h[c].popularity
})
}
return {
total: f.length,
array: f,
metadata: b
}
},
"@suggest_playlists_snapshot": function(d, f) {
this.suggest(d.args, f, this.preparePlaylists)
},
parsePlaylists: function(d) {
var d = d.playlist,
f = [],
b = [];
if (d) for (var c = 0, a = d.length; c < a; c++) {
var g = d[c];
f.push(g.uri);
var i = {
image: null,
name: g.name,
popularity: g.popularity,
uri: g.uri
};
if (typeof g.image === "string") i.image = Spotify.App.SourceURLs.small + g.image;
b.push(i)
}
return {
total: f.length,
array: f,
metadata: b
}
}
})
})();
(function() {
var d = Spotify.Link;
new Spotify.App.Responder({
_ready: !1,
init: function(d) {
(this.service = d.toplist).onReady(this.start, this)
},
start: function() {
this._ready = !0;
this.unqueue()
},
reply: function(d, f, b) {
for (var c = [], a = 0, g = b.length; a < g; a++) c.push(b[a].toString());
f = this.createSnapshot(f, c);
d.send(f)
},
handleError: function(d, f) {
var b, c;
switch (f.code) {
case 404:
b = "not-found";
c = "No toplist found.";
break;
default:
b = "transient", c = "Possible issues with the toplist service."
}
return d.fail(b, c)
},
requestForUser: function(d, f, b, c) {
this.service.lookupForUser(f, d, this.reply.bind(this, c, b), this.handleError.bind(this, c))
},
requestForRegion: function(d, f, b, c) {
this.service.lookupForRegion(f, d, this.reply.bind(this, c, b), this.handleError.bind(this, c))
},
"@toplist_user_tracks_snapshot": function(h, f) {
var b = h.args,
c = h.args[0] ? d.fromString(b[0]).username : null;
c == "@" && (c = null);
this.requestForUser(this.service.TRACK, c, b, f)
},
"@toplist_user_albums_snapshot": function(h, f) {
var b = h.args,
c = h.args[0] ? d.fromString(b[0]).username : null;
c == "@" && (c = null);
this.requestForUser(this.service.ALBUM, c, b, f)
},
"@toplist_user_artists_snapshot": function(h, f) {
var b = h.args,
c = h.args[0] ? d.fromString(b[0]).username : null;
c == "@" && (c = null);
this.requestForUser(this.service.ARTIST, c, b, f)
},
"@toplist_user_playlists_snapshot": function(h, f) {
var b = h.args,
c = h.args[0] ? d.fromString(b[0]).username : null;
c == "@" && (c = null);
this.requestForUser(this.service.PLAYLIST, c, b, f)
},
"@toplist_region_tracks_snapshot": function(d, f) {
var b = d.args;
this.requestForRegion(this.service.TRACK, b[0] || null, b, f)
},
"@toplist_region_albums_snapshot": function(d, f) {
var b = d.args;
this.requestForRegion(this.service.ALBUM, b[0] || null, b, f)
},
"@toplist_region_artists_snapshot": function(d, f) {
var b = d.args;
this.requestForRegion(this.service.ARTIST, b[0] || this._country, b, f)
},
"@toplist_artist_tracks_snapshot": "artist_top_tracks_snapshot"
})
})();
(function() {
var d = Spotify.Link;
new Spotify.App.Responder({
_ready: !1,
_session: null,
_requestBuffer: new Spotify.App.RequestBuffer,
init: function(d) {
window._core = d;
this.use({
session: d.user,
social: d.social,
socialGraph: d.socialGraph
})
},
start: function() {
var d = function() {
this._ready = !0;
this.unqueue()
}.bind(this);
this.getSession({
send: d,
fail: d
})
},
flushRequests: function() {
this.queryService()
},
"@session_query": function(d, f) {
if (this._session) return f.send(this._session);
else this.getSession(f)
},
getSession: function(d) {
this.session.getUserInfo(this.prepareSessionInfo.bind(this, d), d.fail.bind(d, "transient", "Cannot fetch session."))
},
prepareSessionInfo: function(d, f) {
var b = this._session = this.parseSessionInfo(f);
d.send(b)
},
parseSessionInfo: function(d) {
d = d.response;
return {
device: "web",
online: !0,
country: d.country,
product: d.catalogue,
testGroup: d.ab_test_group,
_username: d.user
}
},
"@session_event_wait": function(d, f) {
f.persist()
},
queryService: function() {
var d = this._requestBuffer.takeIds();
d.length && this.social.getUsers(d, "complete", this.format.bind(this, d), this.handleError.bind(this, d))
},
format: function(h, f) {
for (var b = this._requestBuffer, c = null, a = 0, g = h.length; a < g; a++) {
var i = h[a];
(c = f[a]) ? (c = this.parseUser(c), c.currentUser = i == this._session._username) : c = {
error: "not-found",
message: "The user does not exist."
};
this.store(d.profileLink(i).toURI(), "parsed.metadata", c);
for (var i = b.takeReplies(i), n = i.length; n--;) i[n].send(c)
}
},
handleError: function(d) {
for (var f = this._requestBuffer, b = 0, c = d.length; b < c; b++) for (var a = f.takeReplies(d[b]), g = a.length; g--;) a[g].fail("transient", "Could not complete request")
},
parseUser: function(d) {
var f = d.image_url,
b = f.match(/^spotify:image:(.+)/);
b && (f = Spotify.App.SourceURLs.avatar + b[1]);
f = {
username: d.username,
name: d.full_name || d.username,
image: f,
identifier: ""
};
f.subscribed = !! this.socialGraph.isSubscribed([d.username])[0];
return f
},
"@user_metadata": function(h, f) {
var b = this._requestBuffer,
c = h.args[0];
try {
var a = d.fromString(c);
if (a.type != "profile") throw Error();
} catch (g) {
return f.fail({
error: "invalid-uri",
message: "Not a valid user URI."
})
}
if (a.username == "@") a.username =
this._session._username;
if (c = this.retrieve(a.toString(), "parsed.metadata")) return c.currentUser = a.username == this._session._username, f.send(c);
else b.push(a.username, f)
}
})
})();
Spotify.lockStorage();
Spotify.Web.BrowserDetect = {
init: function() {
this.browser = this._searchString(this.dataBrowser) || "An unknown browser";
this.version = this._searchVersion(navigator.userAgent) || this._searchVersion(navigator.appVersion) || "an unknown version";
this.OS = this._searchString(this.dataOS) || "an unknown OS"
},
_searchString: function(d) {
for (var h = 0; h < d.length; h++) {
var f = d[h].string,
b = d[h].prop;
this.versionSearchString = d[h].versionSearch || d[h].identity;
if (f) {
if (f.indexOf(d[h].subString) != -1) return d[h].identity
} else if (b) return d[h].identity
}
},
_searchVersion: function(d) {
var h = d.indexOf(this.versionSearchString);
return h == -1 ? void 0 : parseFloat(d.substring(h + this.versionSearchString.length + 1))
},
dataBrowser: [{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
}, {
string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
}, {
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
}, {
prop: window.opera,
identity: "Opera",
versionSearch: "Version"
}, {
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
}, {
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
}, {
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
}, {
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
}, {
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
}, {
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
}, {
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
}, {
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}],
dataOS: [{
string: navigator.platform,
subString: "Win",
identity: "Windows"
}, {
string: navigator.platform,
subString: "Mac",
identity: "Mac"
}, {
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
}, {
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}]
};
Spotify.Web.ScrollBlocker = function(d, h) {
this.publisher = h;
this.blocker = d
};
Spotify.Web.ScrollBlocker.prototype.init = function() {
this.publisher.subscribe(Spotify.Web.PublisherMessages.SCROLL_BLOCK, this);
this.publisher.subscribe(Spotify.Web.PublisherMessages.SCROLL_ALLOW, this)
};
Spotify.Web.ScrollBlocker.prototype.activate = function() {
this.blocker.style.display = "block"
};
Spotify.Web.ScrollBlocker.prototype.deactivate = function() {
this.blocker.style.display = "none"
};
Spotify.Web.ScrollBlocker.prototype.onNotify = function(d) {
switch (d.messageType) {
case Spotify.Web.PublisherMessages.SCROLL_BLOCK:
this.activate();
break;
case Spotify.Web.PublisherMessages.SCROLL_ALLOW:
this.deactivate()
}
};
Spotify.Web.SocialData = function(d, h, f) {
Spotify.Web.EventTarget.call(this);
var b = this;
this._userFirstName = this._userImage = "";
this._fbComplete = this._apComplete = !1;
var c = function() {
d.notify(Spotify.Web.PublisherMessages.SOCIAL_DATA_SUCCESS, {
name: b._userFirstName,
image: b._userImage
})
},
a = function() {
f.getUserImage(function(a) {
f.getUsersName(function(d) {
var g = a.message[0];
if (b._userImage === "" && g && g.url !== "") b._userImage = g.url;
if (b._userFirstName === "" && d.message.first_name && d.message.first_name !== "") b._userFirstName =
d.message.first_name;
b._fbComplete = !0;
c()
})
})
},
g = function() {
h.getSocialDataForCurrentUser(function(a) {
b._apComplete = !0;
if (a) {
if (a.image_url !== "") b._userImage = a.image_url;
if (a.full_name !== "") b._userFirstName = a.full_name.split(" ")[0];
c()
}
})
};
this.init = function() {
g();
d.subscribe(Spotify.Web.PublisherMessages.FB_APP_CONNECTED, b)
};
this.onNotify = function(b) {
b.messageType === Spotify.Web.PublisherMessages.FB_APP_CONNECTED && (this._userFirstName === "" || this._userImage === "") && a()
}
};
var _ = function(d) {
return "undefined" != typeof spotLang && spotLang[d] ? spotLang[d] : d.replace("_", " ")
};
Spotify.Web.Static = function() {
this.preloadImage = function(d, h) {
var f = new Image;
f.src = d;
if (typeof h !== "undefined") f.onload = h
};
this.loadScript = function(d) {
var h = document.createElement("script");
h.type = "text/javascript";
h.async = !0;
h.src = d;
d = document.getElementsByTagName("script")[0];
d.parentNode.insertBefore(h, d)
}
};
Spotify.Web.EventTarget = function() {
var d = {};
this.bind = function(h, f, b) {
var c = {
callback: f,
context: b
},
a = !1,
g;
d[h] === void 0 && (d[h] = []);
g = d[h];
for (var i = 0; i < g.length; i++) if (g[i].callback === f && g[i].context === b) {
a = !0;
break
}
a === !1 && d[h].push(c)
};
this.trigger = function(h, f) {
var b = d[h],
c;
if (typeof b !== "undefined") for (c = 0; c < b.length; c++) {
var a = b[c];
a.callback.call(a.context, {
type: h,
sender: this,
params: f
})
}
};
this.unbind = function(h, f, b) {
var c, a = d[h];
if (typeof a !== "undefined") {
for (var g = 0; g < a.length; g++) if (a[g].callback === f && a[g].context === b) {
c = g;
break
}
c !== -1 && d[h].splice(c, 1)
}
}
};
Spotify.Web.Publisher = function() {
var d = {},
h = function(f) {
d[f] === void 0 && (d[f] = []);
return d[f]
};
this.subscribe = function(d, b) {
if (!d) throw Error("Spotify.Web.Publisher message type must be set");
if (!b) throw Error("Spotify.Web.Publisher listener object must be set");
var c = h(d);
c.indexOf(b) === -1 && c.push(b)
};
this.unsubscribe = function(d, b) {
var c = h(d),
a = c.indexOf(b);
a > -1 && c.splice(a, 1)
};
this.notify = function(d, b, c) {
for (var a = h(d), g = 0; g < a.length; g++) a[g].onNotify({
messageType: d,
message: b,
origin: c
})
}
};
Spotify.Web.PublisherMessages = {
ERROR: "ERROR",
APPLICATION_STATE_CHANGED: "APPLICATION_STATE_CHANGED",
APPLICATION_STATE_PUSH: "APPLICATION_STATE_PUSH",
APPLICATION_STATE_REPLACE: "APPLICATION_STATE_REPLACE",
APPLICATION_OPEN_URI: "APPLICATION_OPEN_URI",
APPLICATION_POST_MESSAGE: "APPLICATION_POST_MESSAGE",
APPLICATION_ENABLED: "APPLICATION_ENABLED",
APPLICATION_VERSION_CHANGED: "APPLICATION_VERSION_CHANGED",
APPLICATION_CLOSED: "APPLICATION_CLOSED",
APPLICATION_DISPOSED: "APPLICATION_DISPOSED",
CHROME_READY: "CHROME_READY",
FB_APP_CONNECTED: "FB_APP_CONNECTED",
FB_APP_NOT_AUTHENTICATED: "FB_APP_NOT_AUTHENTICATED",
FB_APP_UNKNOWN: "FB_APP_UNKNOWN",
FB_CONNECTION_FAILURE: "FB_CONNECTION_FAILURE",
USER_AUTHENTICATED: "USER_AUTHENTICATED",
USER_AUTHENTICATION_FAILURE: "USER_AUTHENTICATION_FAILURE",
WINDOW_FOCUS: "WINDOW_FOCUS",
SCROLL_ALLOW: "SCROLL_ALLOW",
SCROLL_BLOCK: "SCROLL_BLOCK",
SUGGEST_SHOW: "SUGGEST_SHOW",
SUGGEST_HIDE: "SUGGEST_HIDE",
SUGGEST_SHOWN: "SUGGEST_SHOWN",
SUGGEST_HIDDEN: "SUGGEST_HIDDEN",
SOCIAL_DATA_SUCCESS: "SOCIAL_DATA_SUCCESS"
};
Spotify.Web.PopupWindow = function(d, h) {
Spotify.Web.EventTarget.call(this);
var f = this,
d = d || {},
b = !1,
c = null,
a = d.width || 220,
g = null,
i = {
url: d.url,
id: d.id || null,
wrapper: d.wrapper,
iframe: d.iframe,
preventScrolling: d.preventScrolling || !1,
hideOnWindowResize: d.hideOnWindowResize || !1,
postShowCallback: d.postShowCallback,
postHideCallback: d.postHideCallback
},
n = function(a) {
if (a.source == i.iframe.contentWindow) switch (a = JSON.parse(a.data), a.type) {
case "POPUP_WINDOW_CLOSE":
f.hide();
break;
case "POPUP_WINDOW_RESIZE":
f.resize(a.height, a.width)
}
},
l = function(a) {
i.iframe.contentWindow.postMessage(JSON.stringify({
type: a
}), "*")
};
this.initialize = function() {
if (!i.url) throw Error("Application URL not specified.");
if (!i.iframe) {
var a = document.createElement("iframe");
a.setAttribute("id", "app-" + i.url);
a.setAttribute("frameBorder", "no");
a.style.width = "100%";
a.style.height = "100%";
i.iframe = a
}
if (!i.wrapper) i.wrapper = document.createElement("div"), i.wrapper.appendChild(i.iframe);
i.iframe.src = i.url;
window.addEventListener("message", n, !1);
if (i.hideOnWindowResize) this.onWindowResize =
this.onWindowResize.bind(this), window.addEventListener("resize", this.onWindowResize, !1);
h.notify(Spotify.Web.PublisherMessages.APPLICATION_STATE_CHANGED, {
link: Spotify.Link.applicationLink(i.id),
iframe: i.iframe
})
};
this.getFrame = function() {
return i.iframe || null
};
this.onWindowResize = function() {
this.hide()
};
this.getElement = function() {
return i.wrapper
};
this.getWidth = function() {
return a
};
this.getUrl = function() {
return i.url
};
this.updateSize = function() {
if (b) i.wrapper.style.width = a + "px", i.wrapper.style.height =
c + "px"
};
this.resize = function(b, d) {
c = b;
if (d && (a = d, g)) i.wrapper.style.left = g - d / 2 + "px";
this.updateSize()
};
this.isVisible = function() {
return b
};
this.show = function(a) {
if (!b) {
this.trigger("onBeforeShow");
try {
b = !0;
this.updateSize();
if (a) i.wrapper.style.left = a.left + "px", a.direction == "top" ? (i.wrapper.style.bottom = "auto", i.wrapper.style.top = a.top + "px") : (i.wrapper.style.top = "auto", i.wrapper.style.bottom = a.bottom + "px"), i.wrapper.className = "popup-area", i.wrapper.addClass(a.direction), i.wrapper.addClass(a.arrow), g = a.arrowLeft;
i.wrapper.addClass("show");
Browser.firefox && this.getElement().id === d.id + "-area" && document.activeElement.blur();
d.showMessage && h.notify(d.showMessage);
i.preventScrolling && h.notify(Spotify.Web.PublisherMessages.SCROLL_BLOCK);
i.postShowCallback && i.postShowCallback();
l("WINDOW_FOCUS")
} finally {
this.trigger("onAfterShow")
}
}
};
this.hide = function() {
if (b) b = !1, i.wrapper.removeClass("show"), i.wrapper.style.height = "", d.hideMessage && h.notify(d.hideMessage), i.postHideCallback && i.postHideCallback();
window.focus();
l("WINDOW_CLOSED");
setTimeout(function() {
i.preventScrolling && h.notify(Spotify.Web.PublisherMessages.SCROLL_ALLOW)
}, 250)
}
};
Spotify.Web.PopupManager = function(d, h, f) {
var b = {},
c = !1,
a = function() {
c = !0
},
g = function() {
c = !1
};
this.registerPopup = function(c, n) {
var l = f.ownerDocument.createElement("div");
l.className = "popup-area";
l.setAttribute("id", c + "-area");
var m = f.ownerDocument.createElement("iframe");
m.setAttribute("id", c);
m.setAttribute("tabindex", "-1");
m.setAttribute("frameborder", "0");
m.setAttribute("scrolling", "no");
m.setAttribute("allowTransparency", "true");
l.appendChild(m);
f.appendChild(l);
l = new Spotify.Web.PopupWindow({
url: d.getAppUrl("/" + c + "/"),
id: c,
wrapper: l,
iframe: l.querySelectorAll("iframe")[0],
hideMessage: n.hideMessage,
showMessage: n.showMessage,
preventScrolling: n.preventScrolling,
hideOnWindowResize: n.hideOnWindowResize,
width: n.width
}, h);
l.resize(200);
b[c] = l;
l.bind("onBeforeShow", a);
l.bind("onAfterShow", g)
};
this.initializePopups = function() {
for (var a in b) b[a].initialize()
};
this.popup = function(a, c) {
var d = parseInt(a.args[0], 10),
g = parseInt(a.args[1], 10),
o = parseInt(a.args[2], 10),
k = parseInt(a.args[3], 10);
if (!d || !g) throw Error("popup can only be triggered for popup URIs");
if (!c) throw Error("unknown origin");
var p = b[a.id];
if (!p) throw Error("cannot find popup with id", a.id);
var q = Spotify.Web.Utils.getWindowPosition(c),
s;
d += q.left;
q = g + q.top;
s = 0;
var u = "top",
w = "middle",
v = f.ownerDocument.body.offsetWidth,
t = p.getWidth();
d -= t / 2 - o / 2;
q += k + 10;
q + 300 > window.innerHeight && window.innerHeight > 500 && (s = window.innerHeight - g + 10, u = "bottom");
d + t > v && (d = v - t - 10, w = "right");
a.args.splice(0, 4);
h.notify(Spotify.Web.PublisherMessages.APPLICATION_STATE_CHANGED, {
link: a,
iframe: p.getFrame()
});
p.show({
left: d,
top: q,
bottom: s,
arrowLeft: d + t / 2,
direction: u,
arrow: w
})
};
this.closeAll = function() {
if (!c) for (var a in b) b[a].isVisible() && b[a].hide()
}
};
Spotify.Web.Window = function(d) {
Spotify.Web.EventTarget.call(this);
var h = this,
d = d || {},
f = d.url,
b = d.iframe,
c = function(a) {
f.indexOf(a.origin) === 0 && a.origin !== "" && h.trigger("onMessage", a.data)
};
this.initialize = function() {
if (!f) throw Error("Application URL not specified.");
if (!b) {
var a = document.createElement("iframe");
a.setAttribute("frameBorder", "no");
a.style.width = "100%";
a.style.height = "100%";
b = a
}
window.addEventListener("message", c);
a = "app-" + Spotify.Web.Utils.appNameFromUrl(f);
b.setAttribute("id", a);
b.src = f
};
this.getElement = function() {
return b
};
this.getUrl = function() {
return f
};
this.show = function() {
b.style.display = "block"
};
this.hide = function() {
b.style.display = "none"
}
};
Spotify.Web.URLParser = function() {
var d = {},
h = /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/;
d.parseURL = function(d, b) {
var d = b ? d.match(h) : decodeURI(d).match(h),
c = {
protocol: d[1] || null,
user: d[2] || null,
domain: d[4] || null,
query: d[8] || null,
port: d[5] || null,
hash: d[9] || null,
path: ((d[6] || "") + (d[7] || "")).replace(/^\/|\/$/g, "") || null,
url: d[0]
};
if (c.path) c.pathSegments = c.path.replace(/^\/|\/$/g, "").split("/");
if (c.hash) c.hashSegments =
c.hash.replace(/^\/|\/$/g, "").split("/");
if (c.query) {
c.params = {};
for (var a = /([^=&]+)\=([^=&]+)/g, g = a.exec(c.query); g;) c.params[g[1]] = g[2], g = a.exec(c.query)
}
return c
};
d.isRoot = function(f) {
return (f = d.parseURL(f)) && f.path === null
};
return d
}();
Spotify.Web.Notification = function(d) {
Spotify.Web.EventTarget.call(this);
var d = d || {},
h = d.message || "",
f = d.id || null,
b = d.timeout,
c = this,
a = null;
this.initialize = function() {
a = document.createElement("div");
var b = document.createElement("p");
b.textContent = h;
var d = document.createElement("div");
d.onclick = function() {
c.trigger("onclose", {})
};
a.appendChild(b);
a.appendChild(d)
};
this.getElement = function() {
return a
};
this.getId = function() {
return f
};
this.getTimeout = function() {
return b
}
};
Spotify.Web.NotificationArea = function(d) {
var d = d || {},
h = d.element || {},
f = null,
b = [],
c = {},
a = function(a) {
if (a) return c[a]
},
g = function(a) {
var d = b.indexOf(a);
d > -1 && (b.splice(d, 1), f.removeChild(a.getElement()), a.getId() && delete c[a.getId()])
},
i = function(a) {
b.push(a);
f.appendChild(a.getElement());
a.getId() && (c[a.getId()] = a);
a.getTimeout() && setTimeout(function() {
g(a)
}, a.getTimeout())
};
this.initialize = function() {
f = h;
if (f === null) throw Error("Spotify.Web.NotificationArea element not found");
};
this.show = function(b) {
var c;
c = a(b.id);
if (!c) return c = new Spotify.Web.Notification(b), c.initialize(), c.bind("onclose", function(a) {
g(a.sender)
}), i(c), c
};
this.hide = function(b) {
(b = a(b)) && g(b)
}
};
Spotify.Web.Dialog = function(d) {
var d = d || {},
h = d.element,
f = !1,
b = function() {
c()
},
c;
this.initialize = function() {
if (!h) throw Error("Spotify.Web.Dialog element not specified");
h.querySelector("button").onclick = b
};
this.show = function(a) {
var b = h.querySelector("p");
b.innerHTML = a.message;
b.className = a.className;
var b = h.querySelector("button"),
d = h.querySelector(".buttonContainer");
a.button ? (b.innerHTML = a.button, c = a.action, d.style.display = "block") : d.style.display = "none";
h.style.display = "block";
f = !0
};
this.hide =
function() {
h.style.display = "none";
f = !1
};
this.isVisible = function() {
return f
}
};
Spotify.Web.ErrorTypes = {
SESSION_LOST: "SESSION_LOST",
TOKEN_LOST: "TOKEN_LOST",
NO_SOUND_CAPABILITIES: "NO_SOUND_CAPABILITIES",
AD_BLOCK_DETECTED: "AD_BLOCK_DETECTED",
CONNECTION_RESTORED: "CONNECTION_RESTORED",
CONNECTION_LOST: "CONNECTION_LOST",
CONNECTING: "CONNECTING",
TRACK_NOT_PLAYABLE: "TRACK_NOT_PLAYABLE",
WAIT_FOR_COMMERCIAL_TO_FINISH: "WAIT_FOR_COMMERCIAL_TO_FINISH",
FLASH_NOT_AVAILABLE: "FLASH_NOT_AVAILABLE",
FB_CONNECTING_TO: "FB_CONNECTING_TO",
FB_CONNECTION_FAILED: "FB_CONNECTION_FAILED",
APPLICATION_RELOAD_NEEDED: "APPLICATION_RELOAD_NEEDED",
UNCAUGHT_EXCEPTION: "UNCAUGHT_EXCEPTION"
};
Spotify.Web.ErrorMessages = {
FLASH_NOT_AVAILABLE: {
message: _("flash_not_installed"),
className: "normal",
button: _("get_flash"),
action: function() {
window.open("http://get.adobe.com/flashplayer/")
}
},
SESSION_LOST: {
message: _("session_lost"),
className: "normal",
button: _("login"),
action: function() {
location.href = "/login/"
}
},
NO_SOUND_CAPABILITIES: {
message: _("no_sound_capabilites"),
className: "normal",
button: _("exit"),
action: function() {
window.open("/login/")
}
},
APPLICATION_RELOAD_NEEDED: {
message: _("reload_needed"),
className: "normal",
button: _("reload"),
action: function() {
window.location.reload()
}
},
CONNECTING: {
message: _("connecting_to_Spotify"),
className: "indicator"
},
CONNECTION_LOST: {
message: _("cant_connect"),
className: "indicator"
},
FB_CONNECTING_TO: {
message: _("connecting_to_Facebook"),
className: "indicator"
},
FB_CONNECTION_FAILED: {
message: _("Facebook_connection_failed"),
className: "indicator"
}
};
Spotify.Web.Error = function(d) {
var d = d || {},
h = d.publisher,
f = d.element,
b = d.dialog,
c = d.timeout,
a = null,
g = null;
this.initialize = function() {
if (!h) throw Error("Spotify.Web.Error - Publisher instance is missing");
if (!f) throw Error("Spotify.Web.Error container not specified");
if (!b) throw Error("Spotify.Web.Error dialog element not specified");
a = new Spotify.Web.NotificationArea({
element: f
});
a.initialize();
g = new Spotify.Web.Dialog({
element: b
});
g.initialize();
h.subscribe(Spotify.Web.PublisherMessages.ERROR, this)
};
this.onNotify = function(b) {
var b = b.message,
d = Spotify.Web.ErrorTypes,
f = Spotify.Web.ErrorMessages;
switch (b.type) {
case d.TRACK_NOT_PLAYABLE:
switch (b.response) {
case "Rate limit reached":
d = _("track_unavailable_rate_limit");
break;
case "Song only on storage":
d = _("track_unavailable_only_on_storage");
break;
case "Track restricted":
d = _("track_unavailable");
break;
default:
d = "Track is currently not available"
}
a.show({
message: d,
id: b.type + "_" + b.trackUri,
timeout: c
});
break;
case d.WAIT_FOR_COMMERCIAL_TO_FINISH:
d = _("song_will_play_after_ad");
a.show({
message: d,
id: b.type,
timeout: c
});
break;
case d.SESSION_LOST:
g.show(f.SESSION_LOST);
break;
case d.TOKEN_LOST:
d = _("token_lost");
a.show({
message: d,
id: "token_lost",
timeout: c
});
break;
case d.AD_BLOCK_DETECTED:
d = _("ad_block_detected");
a.show({
message: d,
id: "adblocker_detected",
timeout: c + 1E4
});
break;
case d.NO_SOUND_CAPABILITIES:
g.show(f.NO_SOUND_CAPABILITIES);
break;
case d.FLASH_NOT_AVAILABLE:
g.show(f.FLASH_NOT_AVAILABLE);
break;
case d.APPLICATION_RELOAD_NEEDED:
g.show(f.APPLICATION_RELOAD_NEEDED);
break;
case d.CONNECTION_LOST:
g.show(f.CONNECTION_LOST);
break;
case d.CONNECTING:
g.show(f.CONNECTING);
break;
case d.FB_CONNECTING_TO:
g.show(f.FB_CONNECTING_TO);
break;
case d.FB_CONNECTION_FAILED:
g.hide(f.FB_CONNECTING_TO);
g.show(f.FB_CONNECTION_FAILED);
break;
case d.CONNECTION_RESTORED:
g.hide(f.CONNECTION_LOST);
g.hide(f.CONNECTING);
break;
default:
a.hide(b.type)
}
}
};
Spotify.Web.FeatureDetect = new
function() {
return {
testWebSockets: function() {
return window.WebSocket
},
testHTML5Audio: function() {
var d = document.createElement("audio");
return !(!d.canPlayType || !d.canPlayType("audio/mpeg;").replace(/no/, ""))
},
getFlashVersion: function() {
return swfobject.getFlashPlayerVersion()
},
hasFlashMin: function() {
return swfobject.hasFlashPlayerVersion("9")
},
adBlockCheck: function() {
var d = document.getElementById("ads");
if (d) {
if (d.offsetHeight === 0) return !0
} else
return !0;
document.body.removeChild(d);
return !1
}
}
};
Spotify.Web.Menu = function(d) {
Spotify.Web.EventTarget.call(this);
var h = this,
d = d || {},
f = d.publisher,
b = d.elements,
c = d.defaultId || "",
a = {},
g = !1,
i = null,
n = null,
l = null,
m = null,
o = function(b) {
b || (b = c);
for (var d = 0; d < a.length; d++) a[d].className = a[d].getAttribute("id") !== "nav-" + b ? "" : "current"
},
k = function(a) {
a.onmousedown = function() {
if (g) {
var b = a.getAttribute("data-href");
h.trigger("onAppOpen", {
id: b
})
}
}
},
p = function() {
g = !0;
for (var b = 0; b < a.length; b++) a[b].className = a[b].className.indexOf("current") === -1 ? "" : "current"
},
q = function(a) {
if (!n) return !1;
if (!m && a.image !== "") {
var b = new Image;
b.onload = function() {
n.appendChild(this);
setTimeout(function() {
b.className = "show"
}, 10)
};
m = b.src = a.image
}
if (!l && a.name !== "") l = n.textContent = a.name;
l && m && (n.parentNode.className += " show")
};
this.initialize = function() {
if (!f) throw Error("Publisher instance not specified.");
if (!b) throw Error("List of DOMElements not specified.");
a = b;
f.subscribe(Spotify.Web.PublisherMessages.APPLICATION_STATE_CHANGED, this);
f.subscribe(Spotify.Web.PublisherMessages.APPLICATION_ENABLED, this);
f.subscribe(Spotify.Web.PublisherMessages.SUGGEST_SHOWN, this);
f.subscribe(Spotify.Web.PublisherMessages.SUGGEST_HIDDEN, this);
f.subscribe(Spotify.Web.PublisherMessages.SOCIAL_DATA_SUCCESS, this);
for (var c = 0; c < a.length; c++) a[c].id === "nav-profile" ? n = a[c] : k(a[c])
};
this.highlightMenu = function(a) {
i = a;
o(a)
};
this.onNotify = function(a) {
switch (a.messageType) {
case Spotify.Web.PublisherMessages.SUGGEST_SHOWN:
o("search");
break;
case Spotify.Web.PublisherMessages.SUGGEST_HIDDEN:
o(i);
break;
case Spotify.Web.PublisherMessages.APPLICATION_ENABLED:
p();
break;
case Spotify.Web.PublisherMessages.SOCIAL_DATA_SUCCESS:
q(a.message)
}
};
this.disable = function() {
g = !1;
for (var b = 0; b < a.length; b++) a[b].className = "disabled"
};
this.enable = function() {
p()
}
};
Spotify.Web.Credentials = function(d) {
var h = this,
f = null,
b = 0;
this.cache = function(c, a) {
b = (new Date).getTime() + a * 1E3;
f = c
};
this.get = function(c, a) {
var g = (new Date).getTime();
f && b > g ? c(f) : (new Request({
url: d,
method: "post",
onSuccess: function(a) {
a = JSON.parse(a);
!a.config || !a.config.credentials ? window.location = "/logout/" : (h.cache(a.config.credentials[0], a.config.credentials[1]), c(a.config.credentials[0]))
},
onFailure: a,
onException: a
})).send()
}
};
Spotify.Web.Tracking = function(d, h, f) {
window._gaq = window._gaq || [];
this.initialize = function() {
if (f.gaId) {
_gaq.push(["_setAccount", f.gaId]);
h.loadScript("//ssl.google-analytics.com/ga.js");
var b = d.subscribe,
c = Spotify.Web.PublisherMessages;
b(c.APPLICATION_STATE_PUSH, this);
b(c.ERROR, this);
b(c.CHROME_READY, this);
b(c.WINDOW_FOCUS, this)
}
};
this.onNotify = function(b) {
var c = b.message,
a = Spotify.Web.PublisherMessages;
switch (b.messageType) {
case a.APPLICATION_STATE_PUSH:
this.pageView(c.url);
break;
case a.WINDOW_FOCUS:
this.event("Window", b.messageType, c.type, 0, !0);
break;
case a.CHROME_READY:
this.xhrLog(b.messageType);
break;
case a.ERROR:
this.errors(c)
}
};
this.pageView = function(b) {
_gaq.push(["_trackPageview", b])
};
this.event = function(b, c, a, d, f) {
_gaq.push(["_trackEvent", b, c, a, d, f])
};
this.handleException = function(b, c, a, d, f) {
this.pageView("/ga-log/exc/" + b + "/" + escape(c) + "/" + escape(a) + "/" + escape(d) + "/" + f + "/")
};
this.xhrLog = function(b) {
(new Request({
url: "/xhr/json/log.php",
method: "get"
})).send("type=" + b + "&t=" + (new Date).getTime())
};
this.errors =
function(b) {
var c = "",
a = "",
c = Spotify.Web.ErrorTypes,
d = b.type;
switch (d) {
case c.CONNECTION_LOST:
case c.FLASH_NOT_AVAILABLE:
case c.AD_BLOCK_DETECTED:
case c.FB_CONNECTION_FAILED:
this.xhrLog(d)
}
switch (d) {
case c.CONNECTING:
case c.CONNECTION_LOST:
case c.CONNECTION_RESTORED:
c = "ap";
break;
case c.FLASH_NOT_AVAILABLE:
c = "browser";
break;
case c.APPLICATION_RELOAD_NEEDED:
c = "server";
break;
case c.TRACK_NOT_PLAYABLE:
c = "playback";
a = b.trackUri;
break;
case c.FB_CONNECTING_TO:
case c.FB_CONNECTION_FAILED:
c = "fb";
break;
default:
c = "general"
}
this.pageView("/ga-log/err/" + c + "/" + d + "/" + a)
}
};
Spotify.Web.Logger = function() {
this.fallbackToAlert = this.enabled = !1;
this.consoleUnavailable = typeof console === "undefined" || typeof console.log === "undefined"
};
Spotify.Web.Logger.prototype.log = function() {
this.writeOut("log", arguments)
};
Spotify.Web.Logger.prototype.dir = function() {
this.writeOut("dir", arguments)
};
Spotify.Web.Logger.prototype.warn = function() {
this.writeOut("warn", arguments)
};
Spotify.Web.Logger.prototype.error = function() {
this.writeOut("error", arguments)
};
Spotify.Web.Logger.prototype.info = function() {
this.writeOut("info", arguments)
};
Spotify.Web.Logger.prototype.writeOut = function(d, h) {
if (this.enabled) if (this.consoleUnavailable) this.fallbackToAlert && alert(d + ":" + Array.prototype.slice.call(h).join());
else console[d](Array.prototype.slice.call(h))
};
Spotify.Web.Services = function(d, h, f, b) {
if (!d) throw Error("Service.Metadata instance required");
if (!h) throw Error("Service.Playlist instance required");
var c, a = function(a) {
a = Spotify.Utils.Base62.fromHex(a);
a.length === 21 && (a = "0" + a);
return a
},
g = function(b, c, g, f) {
if (b === c) f(!0, g);
else d.onReady(function() {
try {
d.lookup(c, function(c) {
c = "spotify:track:" + a(c.id);
f(b === c, g)
}, function() {})
} catch (h) {}
})
};
this.getAlbumForTrack = function(b, c, g) {
d.onReady(function() {
try {
d.lookup(b, function(b) {
b = a(b.album.id);
c(b)
}, g)
} catch (f) {
g(f)
}
})
};
this.getTrackIndexInAlbum = function(b, c, g) {
d.onReady(function() {
try {
d.lookup(b, function(b) {
for (var d = 0, f = 0; f < b.disc.length; f++) for (var h = b.disc[f], i = 0; i < h.track.length; i++) {
if (a(h.track[i].id) === c) {
g(d);
return
}
d += 1
}
g(-1)
}, function() {
g(-1)
})
} catch (f) {}
})
};
this.getTrackIndexInPlaylist = function(b, c, d) {
h.list({
uri: b
}, function(b) {
for (var f = b.contents.length, h = !1, i = 0; i < b.contents.length; i++) if (b.contents[i].id !== void 0) {
var q = a(b.contents[i].id);
g("spotify:track:" + c, "spotify:track:" + q, {
index: i
}, function(a, b) {
a ? (h = !0, d(b.index)) : (f -= 1, !h && f === 0 && d(-1))
})
}
}, function() {
d(-1)
})
};
this.getUsername = function(a) {
if (c) a(c);
else f.onReady(function() {
f.getUserInfo(function(b) {
c = b.response.user;
a(c)
}, function() {
a(null)
})
})
};
this.getSocialDataForCurrentUser = function(a) {
this.getUsername(function(c) {
if (!c) return a(null);
b.onReady(function() {
b.getUsers([c], void 0, function(b) {
a(b[0])
}, function() {
a(null)
})
})
})
};
this.isOwnPlaylist = function(a, b) {
this.getUsername(function(c) {
a.type === "application" && a.id === "user" && a.args[0] === c ? b(!0) : a.type === "application" && a.id === "playlist" && a.args[0] === c ? b(!0) : b(!1)
})
}
};
Spotify.Web.AutoPlay = function(d, h, f) {
var b = [new Spotify.Web.FacebookURLSchema, new Spotify.Web.OpenURLSchema],
c = new d.Responder({
playContext: function(a, b) {
b === void 0 && (b = -1);
this.trigger("play_context", {
origin: Spotify.Web.Utils.spotifyUriToOrigin(a),
args: [0, a, b, 0, "autoplay"]
}, function() {}, function() {})
},
pause: function() {
this.trigger("player_pause", {}, function() {}, function() {})
},
resume: function() {
this.trigger("player_play", {}, function() {}, function() {})
},
play: function(a, b, c, d) {
var l = this,
m, o;
try {
m = h.fromString(a), o = m.toURI()
} catch (k) {
return null
}
switch (m.type) {
case "track":
f.getAlbumForTrack(o, function(a) {
var a = "spotify:album:" + a,
b = o.split(":")[2];
f.getTrackIndexInAlbum(a, b, function(b) {
l.playContext(a, b);
c()
})
}, d);
break;
case "playlist":
b ? f.getTrackIndexInPlaylist(o, b, function(a) {
l.playContext(o, a);
c()
}) : (this.playContext(o), c());
break;
case "album":
b ? f.getTrackIndexInAlbum(o, b, function(a) {
l.playContext(o, a);
c()
}) : (this.playContext(o), c());
break;
case "artist":
this.playContext(o + ":top:tracks");
c();
break;
case "artist-toplist":
this.playContext(o), c()
}
}
});
this.shouldPlay = function(a) {
for (var c = !1, d = 0; d < b.length; d++) if (b[d].shouldPlay(a)) {
c = !0;
break
}
return c
};
this.play = function(a, b, d, f) {
c.play(a, b, d, f)
};
this.pause = function() {
c.pause()
};
this.resume = function() {
c.resume()
};
this.playUrl = function(a, c, d) {
for (var f = 0; f < b.length; f++) if (b[f].playUrl(a, this.play, c, d)) break
};
this.getUrl = function(a, c) {
for (var d, h = 0; h < b.length; h++) if (d = b[h].getUrl(a), b[h].shouldPlay(a)) break;
(h = Spotify.Web.Utils.decodeOpenGraphUrl(d)) && h.context === "track" ? f.getAlbumForTrack("spotify:track:" + h.contextId, function(a) {
var b = Spotify.Web.URLParser.parseURL(d);
c(b.protocol + "://" + b.domain + "/album/" + a)
}) : c(d)
}
};
Spotify.Web.Exceptions = function() {
Spotify.EventTarget.call(this);
var d = this,
h = [],
f = function(b, c, a, f, i) {
for (var n = 0; n < h.length; n++) {
try {
h[n].call(this, b, c, a, f, i)
} catch (l) {}
d.trigger(Spotify.Web.ErrorTypes.UNCAUGHT_EXCEPTION, {
module: b,
message: c + " " + a,
url: f,
lineNumber: i
})
}
return !0
};
this.addHandler = function(b) {
h.push(b)
};
this.bindWindow = function(b, c) {
b.onerror = function(a, b, d) {
if (b === "") b = location.href;
f(c, a, "", b, d)
}
};
this.logError = function(b, c, a) {
f(b, c, a, "", "")
}
};
Spotify.Web.Router = function(d, h) {
var f = this,
b;
this.setServices = function(c) {
b = c
};
this.openUri = function(c, a, f) {
c.type !== "application" && (c = c.toAppLink());
f = f || !1;
a = a || "";
c.type === "application" && c.id === "track" ? b.getAlbumForTrack(c.toURI(), function(b) {
b = Spotify.Link.fromString("spotify:album:" + b).toAppLink();
d.openUri(b, a, f)
}) : d.openUri(c, a, f)
};
this.getAppUrl = function(b) {
if (!b) b = h.defaultState.url;
var a = h.settings.apps,
d = h.settings.apps.versions,
f = "";
b.charAt(0) === "/" && (b = b.substr(1, b.length - 1));
var n =
b.split("/"),
b = n[0];
if (b === "user" && (n[2] === "playlist" || n[2] === "starred" || n[2] === "toplist")) b = "playlist";
d[b] !== null && (f = "/" + d[b] + "/");
d = "";
h.settings.apps.cacheBuster && (d = "?v=" + h.settings.apps.cacheBuster);
return a.protocol + "://" + a.prefixes[b] + "-" + b + "." + a.domain + f + d
};
this.openInitialUrl = function(b, a, d) {
var h = Spotify.Web.Utils.openGraphUrlToSpotifyUri(b);
h === "" && (h = "spotify:app:home");
if (h.indexOf(":app:") === -1 || h.indexOf(":app:search" !== -1)) this.openUri(Spotify.Link.fromString("spotify:app:home").toAppLink(), "", !1), h = Spotify.Link.fromString(h).toAppURI();
a.init(d.user, h, function() {
f.openUri(Spotify.Link.fromString(h).toAppLink(), "", !1)
})
}
};
Spotify.Web.Router.History = function(d, h) {
Spotify.Web.EventTarget.call(this);
var f = ["play", "ap", "websockets"],
b = this,
c = 0,
a = 0,
g = function() {
var f = h.getState();
b.trigger("pageChange", {
url: f.url
});
if (a > 0) a -= 1;
else {
var g = f.data.index,
f = 0,
l = "undo";
g > c ? (f = g - c, l = "redo") : g < c && (f = -(c - g));
c = g;
for (g = 0; g < Math.abs(f); g += 1) l === "undo" ? d.undo() : d.redo()
}
};
this.getAddressBarUrl = function() {
var a = h.getPageUrl(),
b = a.indexOf("?"),
c = b > -1,
d = !1,
g;
for (g in f) if (a.indexOf("?" + f[g] + "=") > -1) {
d = !0;
break
}
c && !d && (a = a.substr(0, b));
return a
};
this.push = function(b) {
var d = "/" + b.toURLPath();
c += 1;
a += 1;
h.pushState({
index: c,
link: b
}, "", d)
};
this.replace = function(a) {
url = "/" + a.toURLPath();
h.replaceState({
index: c,
link: a
}, "", url)
};
(function() {
h.Adapter.bind(window, "statechange", g, this)
})()
};
Spotify.Web.StateHistory = {};
Spotify.Web.StateHistory.Commands = {};
Spotify.Web.StateHistory.CommandTypes = {
EMPTY: "EMPTY",
SHOW_SECTION: "SHOW_SECTION",
UPDATE_APP_ARGUMENTS: "UPDATE_APP_ARGUMENTS",
PUSH: "PUSH",
POP: "POP",
MOVE_VIEWPORT: "MOVE_VIEWPORT",
COMPOSED_COMMAND: "COMPOSED_COMMAND",
UPDATE_VIEWPORT_BEGIN: "UPDATE_VIEWPORT_BEGIN",
UPDATE_VIEWPORT_END: "UPDATE_VIEWPORT_END",
BROWSER_HISTORY_PUSH_URL: "BROWSER_HISTORY_PUSH_URL"
};
Spotify.Web.StateHistory.Manager = function(d, h) {
Spotify.Web.EventTarget.call(this);
if (typeof d === "undefined") throw Error("No arguments were supplied while initializing the State History Manager class.");
this.activeSection = null;
var f = this,
b = {},
c = h,
a = new Spotify.Web.StateHistory.Stack,
g = new Spotify.Web.StateHistory.Stack,
i = function(a) {
this.activeSection = b[a.params.id]
},
n = function(a, b) {
a.execute(function(a) {
b && a.type === Spotify.Web.StateHistory.CommandTypes.BROWSER_HISTORY_PUSH_URL && f.trigger("onBrowserHistoryPush", {
link: a.link
});
f.trigger("doCommand", {
command: a
})
})
},
l = function(a) {
var a = new Spotify.Web.StateHistory.App(f.activeSection.id, f.activeSection.viewport.endsAt, a),
b = [];
b.push(new Spotify.Web.StateHistory.Commands.PushApp(f.activeSection, a));
b.push(new Spotify.Web.StateHistory.Commands.MoveViewport(f.activeSection, 1));
b.push(new Spotify.Web.StateHistory.Commands.BrowserHistoryPushUrl(a.link));
a = new Spotify.Web.StateHistory.Commands.ComposedCommand(b);
f.run(a)
},
m = function(a, b) {
var c = [];
c.push(new Spotify.Web.StateHistory.Commands.UpdateAppLink(f.activeSection, f.activeSection.getTopApp(), a));
b || c.push(new Spotify.Web.StateHistory.Commands.BrowserHistoryPushUrl(a));
c = new Spotify.Web.StateHistory.Commands.ComposedCommand(c);
f.run(c, b)
},
o = function(a) {
var b = ["playlist", "starred", "toplist"];
return a.id === "playlist" || a.id === "user" && b.indexOf(a.args[1]) > -1
},
k = function() {
var a = f.activeSection;
a.persistent && a.viewport.endsAt === 0 && f.trigger("onBrowserHistoryReplace", {
link: a.apps[0].link
})
};
this.initialize = function() {
if (typeof d.sections === "undefined") throw Error("No sections were supplied.");
for (var a = 0, c = d.sections.length, f = d.sections; a < c; a += 1) {
var g = f[a].link;
b[g.id] = new Spotify.Web.StateHistory.Section(g, f[a].type, f[a].persistent);
b[g.id].bind("onActive", i, this)
}
};
this.getCurrentLink = function() {
return this.activeSection && this.activeSection.getTopApp() ? this.activeSection.getTopApp().link : null
};
this.run = function(b, c) {
c || (g.push(b), a.clear());
n(b, !c)
};
this.undo = function() {
var b = g.pop().invert();
n(b);
a.push(b);
k();
return b
};
this.redo = function() {
var b = a.pop().invert();
n(b);
g.push(b);
k();
return b
};
this.openUri = function(a, d, g) {
if (typeof a === "undefined") throw Error("openUri needs a Spotify.Link as an argument");
var h = this.getCurrentLink();
if (!(h && a.toURI() === h.toURI())) {
this.trigger("beforeOpenUri", {
link: a
});
var i = a.id,
h = !1,
k;
for (k in b) if (k === i && (h = !0, b[k].type === "popup")) {
this.trigger("onPopup", {
link: a,
origin: d
});
return
}
this.activeSection && this.activeSection.getTopApp().id === "welcome" && this.showSection(b.home, g);
if (h && (!a.args || a.args.length === 0)) this.activeSection !== b[i] ? this.showSection(b[i], g) : this.activeSection.viewport.endsAt !== 0 && this.goToRoot();
else if (g) this.trigger("onBrowserHistoryReplace", {
link: a
}), m(a, !0);
else if (o(a)) this.activeSection.id === "playlist" && this.activeSection.apps.length === 1 ? m(a, g) : c.isOwnPlaylist(a, function(c) {
c ? f.goToRoot(b.playlist, a) : l(a, g)
});
else if (h) if (a.id === "user" && a.args[0]) {
var n = a.args[0];
c.getUsername(function(c) {
c === n ? f.goToRoot(b[i], a) : l(a, g)
})
} else a.args && a.args.length > 0 && this.goToRoot(b[i], a);
else l(a, g)
}
};
this.goToRoot = function(a, b) {
var c = [],
d = this.activeSection;
a && this.activeSection !== a && (c.push(new Spotify.Web.StateHistory.Commands.ShowSection(this.activeSection, a)), d = a);
c.push(new Spotify.Web.StateHistory.Commands.UpdateViewportBegin(d));
for (var f = d.viewport.endsAt + 1; --f;) {
var g = d.apps[f];
c.push(new Spotify.Web.StateHistory.Commands.MoveViewport(d, -1));
c.push(new Spotify.Web.StateHistory.Commands.PopApp(d, g))
}
c.push(new Spotify.Web.StateHistory.Commands.UpdateViewportEnd(d));
b ? (c.push(new Spotify.Web.StateHistory.Commands.UpdateAppLink(d, d.apps[0], b)), d = b) : d = a ? d.getTopApp().link : d.apps[0].link;
c.push(new Spotify.Web.StateHistory.Commands.BrowserHistoryPushUrl(d));
this.run(new Spotify.Web.StateHistory.Commands.ComposedCommand(c))
};
this.showSection = function(a) {
var b = [];
b.push(new Spotify.Web.StateHistory.Commands.ShowSection(this.activeSection, a));
b.push(new Spotify.Web.StateHistory.Commands.BrowserHistoryPushUrl(a.getTopApp().link));
this.run(new Spotify.Web.StateHistory.Commands.ComposedCommand(b))
};
this.moveViewport = function(a) {
if (a !== -1) throw Error("not supported");
this.run(new Spotify.Web.StateHistory.Commands.ComposedCommand([new Spotify.Web.StateHistory.Commands.MoveViewport(this.activeSection, a), new Spotify.Web.StateHistory.Commands.PopApp(this.activeSection, this.activeSection.getTopApp()), new Spotify.Web.StateHistory.Commands.BrowserHistoryPushUrl(this.activeSection.apps[this.activeSection.apps.length - 1 + a].link)]))
};
this.getSection = function(a) {
return typeof b[a] !== "undefined" ? b[a] : null
};
this.isRootActive = function() {
return this.activeSection.viewport.endsAt === 0
};
this.getSections = function() {
return b
};
this.getUndoStack = function() {
return g
};
this.getRedoStack = function() {
return a
};
this.setServices = function(a) {
c = a
}
};
Spotify.Web.StateHistory.Stack = function() {
var d = [];
this.isEmpty = function() {
return d.length === 0
};
this.clear = function() {
d = []
};
this.getLength = function() {
return d.length
};
this.getItemAtIndex = function(h) {
return typeof d[h] !== "undefined" ? d[h] : null
};
this.push = function(h) {
d.push(h)
};
this.pop = function() {
return d.pop()
}
};
Spotify.Web.StateHistory.Section = function(d, h, f) {
Spotify.Web.EventTarget.call(this);
if (typeof d === "undefined") throw Error("The link argument is required!");
this.id = d.id;
this.type = h;
this.persistent = f || !1;
this.apps = [new Spotify.Web.StateHistory.App(this.id, 0, d)];
this.viewport = new Spotify.Web.StateHistory.Viewport;
this.clear = function() {
this.apps = this.apps.slice(0, 1)
};
this.setActive = function() {
this.trigger("onActive", {
id: this.id
})
};
this.getTopApp = function() {
return this.apps[this.apps.length - 1]
}
};
Spotify.Web.StateHistory.App = function(d, h, f) {
if (typeof f === "undefined") throw Error("Argument missing: link");
var b = d + "-app-" + f.toAppURI() + "-" + h + "-" + Date.now();
this.link = f;
this.id = f.id;
this.uri = f.toAppURI();
this.args = f.args || [];
this.updateLink = function(b) {
this.link = b;
this.id = b.id;
this.uri = b.toAppURI();
this.args = b.args || []
};
this.getUniqueId = function() {
return b
}
};
Spotify.Web.StateHistory.Viewport = function() {
this.length = 2;
this.endsAt = 0
};
Spotify.Web.StateHistory.Commands.PushApp = function(d, h) {
this.section = d;
this.app = h;
this.type = Spotify.Web.StateHistory.CommandTypes.PUSH;
this.execute = function(f) {
d.apps.push(h);
f(this)
};
this.invert = function() {
return new Spotify.Web.StateHistory.Commands.PopApp(d, h)
}
};
Spotify.Web.StateHistory.Commands.PopApp = function(d, h) {
this.section = d;
this.app = h;
this.type = Spotify.Web.StateHistory.CommandTypes.POP;
this.execute = function(f) {
d.apps.pop();
f(this)
};
this.invert = function() {
return new Spotify.Web.StateHistory.Commands.PushApp(d, h)
}
};
Spotify.Web.StateHistory.Commands.MoveViewport = function(d, h) {
this.section = d;
this.type = Spotify.Web.StateHistory.CommandTypes.MOVE_VIEWPORT;
this.execute = function(f) {
d.viewport.endsAt += h;
f(this)
};
this.getOffset = function() {
return h
};
this.invert = function() {
return new Spotify.Web.StateHistory.Commands.MoveViewport(d, -1 * h)
}
};
Spotify.Web.StateHistory.Commands.ShowSection = function(d, h) {
this.section = h;
this.app = h.apps[0];
this.type = Spotify.Web.StateHistory.CommandTypes.SHOW_SECTION;
this.execute = function(d) {
this.app = this.section.apps[0];
this.section.setActive(!0);
d(this)
};
this.invert = function() {
return new Spotify.Web.StateHistory.Commands.ShowSection(this.section, d)
}
};
Spotify.Web.StateHistory.Commands.UpdateAppLink = function(d, h, f) {
var b = h.link;
this.section = d;
this.type = Spotify.Web.StateHistory.CommandTypes.UPDATE_APP_ARGUMENTS;
this.execute = function(b) {
h.updateLink(f);
b(this)
};
this.invert = function() {
return this.section.persistent ? new Spotify.Web.StateHistory.Commands.Empty : new Spotify.Web.StateHistory.Commands.UpdateAppLink(d, h, b)
}
};
Spotify.Web.StateHistory.Commands.Empty = function() {
this.type = Spotify.Web.StateHistory.CommandTypes.EMPTY;
this.execute = function(d) {
d(this)
};
this.invert = function() {
return new Spotify.Web.StateHistory.Commands.Empty
}
};
Spotify.Web.StateHistory.Commands.UpdateViewportBegin = function(d) {
this.section = d;
this.execute = function(d) {
d(this)
};
this.type = Spotify.Web.StateHistory.CommandTypes.UPDATE_VIEWPORT_BEGIN;
this.invert = function() {
return new Spotify.Web.StateHistory.Commands.UpdateViewportEnd(d)
}
};
Spotify.Web.StateHistory.Commands.UpdateViewportEnd = function(d) {
this.section = d;
this.type = Spotify.Web.StateHistory.CommandTypes.UPDATE_VIEWPORT_END;
this.execute = function(d) {
d(this)
};
this.invert = function() {
return new Spotify.Web.StateHistory.Commands.UpdateViewportBegin(d)
}
};
Spotify.Web.StateHistory.Commands.BrowserHistoryPushUrl = function(d) {
this.type = Spotify.Web.StateHistory.CommandTypes.BROWSER_HISTORY_PUSH_URL;
this.link = d;
this.execute = function(d) {
d(this)
};
this.invert = function() {
return this
}
};
Spotify.Web.StateHistory.Commands.ComposedCommand = function(d) {
if (!d.length || !(d.length > 0)) throw Error("The ComposedCommand argument must be an array");
this.type = Spotify.Web.StateHistory.CommandTypes.COMPOSED_COMMAND;
this.execute = function(h) {
for (var f = 0; f < d.length; f++) d[f].execute(h)
};
this.invert = function() {
for (var h = [], f = d.length - 1; f >= 0; f--) h.push(d[f].invert());
return new Spotify.Web.StateHistory.Commands.ComposedCommand(h)
};
this.getCommands = function() {
return d
};
this.getCommandAtIndex = function(h) {
h =
d[h];
return typeof h !== "undefined" ? h : null
}
};
Spotify.Web.AppWindow = function(d, h, f, b) {
Spotify.Web.EventTarget.call(this);
var c, a = document.createElement("div"),
g = !0;
this.lastUsedTime = (new Date).getTime();
this.getNode = function() {
if (!c) c = b.createElement("iframe"), c.id = d, c.src = h, this.trigger("onFrameCreated", {
app: f,
node: c
});
this.unmarkForGarbageCollection();
return c
};
this.markForGarbageCollection = function() {
g = !0
};
this.unmarkForGarbageCollection = function() {
g = !1
};
this.dispose = function() {
if (c) this.trigger("onFrameDisposed", {
app: f,
node: c
}), a.appendChild(c), a.innerHTML = "", delete c, c = null
};
this.getId = function() {
return d
};
this.isDisposable = function() {
return g
}
};
Spotify.Web.AppManager = function(d, h, f) {
Spotify.Web.EventTarget.call(this);
var b = this,
c = {},
a = function(a, b) {
return d.getSection(a).apps[b].getUniqueId()
},
g = function(c, g) {
var i = d.getSection(c).apps[g],
o = a(c, g),
k = h(i.link.toURLPath()),
i = new Spotify.Web.AppWindow(o, k, i, f);
i.bind("onFrameCreated", function(a) {
b.trigger("onFrameCreated", a.params)
});
i.bind("onFrameDisposed", function(a) {
b.trigger("onFrameDisposed", a.params)
});
return i
},
i = function(a, b) {
return a.lastUsedTime - b.lastUsedTime
};
this.getActiveFrame =
function() {
var b = d.activeSection,
b = a(b.id, b.viewport.endsAt);
return c[b].getNode()
};
this.get = function(b, d) {
var f = a(b, d);
if (c[f]) return c[f].getNode();
else {
var h = g(b, d);
c[f] = h;
return h.getNode()
}
};
this.dispose = function(b, d) {
if (d !== 0) {
var f = a(b, d);
c[f].markForGarbageCollection();
var f = [],
g;
for (g in c) c[g].isDisposable() && f.push(c[g]);
if (f.length > 0) {
g = f.length - 0;
f.sort(i);
for (var h, p = 0; p < g; p += 1) h = f[p], h.dispose(), delete c[h.getId()]
}
}
};
this.registerAppWindow = function(a, b) {
this.trigger("onFrameCreated", {
app: {
link: b
},
node: a
})
};
this.getFromWindow = function(a) {
var b = null,
d;
for (d in c) if (c.hasOwnProperty(d) && c[d].getNode().contentWindow === a) {
b = c[d];
break
}
return b
};
(function() {
d.bind("doCommand", function(d) {
var f = d.params.command;
f.type === Spotify.Web.StateHistory.CommandTypes.UPDATE_APP_ARGUMENTS && (d = f.section.apps[f.section.viewport.endsAt], f = a(f.section.id, f.section.viewport.endsAt), b.trigger("onFrameUpdated", {
app: d,
node: c[f].getNode()
}))
})
})()
};
Spotify.Web.Queue = function() {
var d = null;
this.execute = function(h) {
d && d.forceFinish();
d = h;
d.execute()
};
this.forceFinish = function() {
d && d.forceFinish()
}
};
Spotify.Web.Queue.TransitionStep = function(d, h) {
var f = !1,
b = null,
c = function() {
try {
d()
} finally {
f = !0
}
};
this.execute = function() {
h ? b = setTimeout(c, h) : c()
};
this.forceFinish = function() {
f || (clearTimeout(b), c())
};
this.delay = h
};
Spotify.Web.Queue.Transition = function(d) {
this.execute = function() {
for (var h = 0; h < d.length; h++) d[h].execute()
};
this.forceFinish = function() {
for (var h = 0; h < d.length; h++) d[h].forceFinish()
}
};
Spotify.Web.View = function(d, h, f) {
Spotify.Web.EventTarget.call(this);
var b = this,
c = {},
a, g = function(a) {
var g = d.getSections()[a],
g = new Spotify.Web.View.Section(g, h, f.ownerDocument);
c[a] = g;
f.appendChild(g.getWrapper());
g.bind("onMoveViewportLeft", function() {
d.moveViewport(-1)
}, b);
g.bind("onFrontPaneUpdate", function(a) {
this.trigger("onFrontPaneUpdate", a.params)
}, b)
},
i = function(b) {
b = b.params.command;
switch (b.type) {
case Spotify.Web.StateHistory.CommandTypes.SHOW_SECTION:
b = c[b.section.id];
if (!b) throw Error("incorrect section id");
a !== b && (a && a.hide(), b.show(), a = b);
break;
case Spotify.Web.StateHistory.CommandTypes.MOVE_VIEWPORT:
var d = b.getOffset();
c[b.section.id].moveViewport(d);
break;
case Spotify.Web.StateHistory.CommandTypes.UPDATE_VIEWPORT_BEGIN:
a.updateViewportBegin();
break;
case Spotify.Web.StateHistory.CommandTypes.UPDATE_VIEWPORT_END:
a.updateViewportEnd()
}
},
n = function() {
a && a.forceQueue()
};
(function() {
var a = d.getSections(),
c;
for (c in a) a.hasOwnProperty(c) && g(a[c].id);
d.bind("doCommand", i, b);
d.bind("beforeOpenUri", n, b)
})()
};
Spotify.Web.View.Section = function(d, h, f) {
Spotify.Web.EventTarget.call(this);
var b = this,
c, a = Array(3),
g = new Spotify.Web.Queue,
i = !1,
n = function() {
b.trigger("onFrontPaneUpdate", {
node: a[a.length - 1].iFrame
})
},
l = function(a) {
a.isRoot() ? a.wrapper.className = "limbo" : c.removeChild(a.wrapper)
},
m = function(a, b, c, d) {
a = new Spotify.Web.Queue.Transition([new Spotify.Web.Queue.TransitionStep(a), new Spotify.Web.Queue.TransitionStep(b, 5), new Spotify.Web.Queue.TransitionStep(c, d ? d : 25)]);
g.execute(a)
},
o = function(a) {
var g =
a === 0,
i = new Spotify.Web.View.Pane(g),
a = h.get(d.id, a);
i.updateIFrame(a);
!g || !c.querySelectorAll(".limbo")[0] ? (i.wrapper = f.createElement("div"), i.wrapper.appendChild(i.iFrame), i.wrapper.addEventListener("click", function() {
b.trigger("onMoveViewportLeft", {})
}), g = f.createElement("div"), g.className = "overlay", i.wrapper.appendChild(g)) : i.wrapper = c.querySelectorAll(".limbo")[0];
return i
},
k = function() {
var b, f, g;
m(function() {
b = a[0];
for (var h = 0; h < a.length - 1; h++) a[h] = a[h + 1], a[h] && (h === a.length - 2 ? (g = a[h], g.updateViewIndex(a.length - h - 1, "fadeIn")) : a[h].updateViewIndex(a.length - h - 1));
a[a.length - 1] = o(d.viewport.endsAt);
f = a[2];
f.updateViewIndex(0, "fadeIn");
c.appendChild(f.wrapper)
}, function() {
f.updateViewIndex(0)
}, function() {
g.updateViewIndex(1);
b && (l(b), h.dispose(d.id, d.viewport.endsAt - d.viewport.length - 1));
n()
})
};
this.getWrapper = function() {
if (!c) {
var a = f.createElement("div");
a.setAttribute("id", "section-" + d.id);
a.className = "hidden";
c = a
}
return c
};
this.show = function() {
if (!a[2]) {
a[2] = o(0);
var b = a[2];
b.updateViewIndex(0);
c.appendChild(b.wrapper)
}
c.className = "active"
};
this.forceQueue = function() {
g.forceFinish()
};
this.hide = function() {
c.className = "hidden"
};
this.moveViewport = function(b) {
if (!i) if (b === 1) k();
else if (b === -1) {
for (var b = a[2], f = a.length - 1; f > 0; f--) a[f] = a[f - 1], a[f] && a[f].updateViewIndex(a.length - f - 1), a[f - 1] = null;
f = d.viewport.endsAt - d.viewport.length;
f >= 0 && (a[0] = o(f), a[0].updateViewIndex(d.viewport.length), f > 0 && c.insertBefore(a[0].wrapper, c.childNodes[1]));
l(b);
h.dispose(d.id, d.viewport.endsAt + 1);
n()
} else
throw Error("not implemented");
};
this.updateViewportBegin =
function() {
i = !0;
for (var b = 0; b < a.length; b++) a[b] && (l(a[b]), h.dispose(d.id, d.viewport.endsAt - a.length + 1 + b), a[b] = null)
};
this.updateViewportEnd = function() {
i = !1;
for (var b = -1, f = d.viewport.endsAt - 2; f <= d.viewport.endsAt; f++) if (b += 1, !(f < 0)) {
var g = o(f);
a[b] = g;
g.updateViewIndex(2 - b);
g.wrapper.parentElement !== c && c.appendChild(g.wrapper)
}
}
};
Spotify.Web.View.Pane = function(d) {
this.wrapper = this.iFrame = null;
this.updateIFrame = function(d) {
this.iFrame = d
};
this.updateViewIndex = function(h, f) {
this.wrapper.className = "index-" + h;
d === !0 && (this.wrapper.className += " root");
f && (this.wrapper.className += " " + f)
};
this.isRoot = function() {
return d
}
};
window._debug = !1;
Spotify = Spotify || {};
Spotify.Web = Spotify.Web || {};
Spotify.Web.App = function() {
var d = {
settings: null,
defaultState: {
url: "home",
title: "What's new - Spotify"
},
spotifyAppId: 134519659678
},
h = {},
f, b, c, a, g, i, n, l, m, o, k, p, q, s, u, w, v, t, y, C, x, z, B, M, H, E, F, D = null,
G = null,
I = [],
J = function() {
var b = p.getAddressBarUrl(),
c = !0;
f.notify(Spotify.Web.PublisherMessages.APPLICATION_ENABLED, {});
y = new Spotify.Web.Services(a.metadata, a.playlist, a.user, a.social);
C = new Spotify.Web.AutoPlay(Spotify.App, Spotify.Link, y, k.getAppUrl);
o.setServices(y);
C.shouldPlay(b) && (c = !1);
Spotify.App.init(a, {
publisher: f,
getAppUrl: k.getAppUrl,
shouldGetSavedState: c
});
if (C.shouldPlay(b)) {
var d = function() {
C.getUrl(b, function(b) {
k.openInitialUrl(b, z, a)
})
},
g = function() {
a.player.unbind("ON_LOAD", g, this);
d()
},
h = function() {
a.player.unbind("CANNOT_PLAY_TRACK", h, this);
a.player.unbind("PLAYBACK_FAILED", h, this);
a.player.unbind("INVALID_TRACK_URI", h, this);
d()
};
a.player.bind("ON_LOAD", g, this);
a.player.bind("CANNOT_PLAY_TRACK", h, this);
a.player.bind("PLAYBACK_FAILED", h, this);
a.player.bind("INVALID_TRACK_URI", h, this);
C.playUrl(b, function() {}, h)
} else k.openInitialUrl(b, z, a);
D = new Spotify.Web.Ads.PixelTracker(a);
D.init();
S();
H = new Spotify.Web.SocialData(f, y, t);
H.init();
q.registerAppWindow(document.getElementById("app-player"), Spotify.Link.fromString("spotify:app:player").toAppLink())
},
O = function() {
var b = document.getElementById("app-player");
n = new Spotify.Web.Window({
url: k.getAppUrl("/player/"),
iframe: b
});
n.bind("onMessage", function(c) {
if (c.params === "playback_started") document.body.className = "started", b.tabIndex = "0";
if (c.params.indexOf("ad_clicked") !== -1) a.adChooser.recordAdEvent("spotify:ad:" + a.player.ad.file_id, "click"), a.player.ad.clicked = !0
});
n.initialize()
},
L = function() {
G && clearTimeout(G);
T();
w || (w = !0, a.metadata.onReady(function() {
a.playlist.onReady(function() {
J();
l.initialize();
m.initializePopups()
})
}), window.addEventListener("beforeunload", Y));
f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.CONNECTION_RESTORED
})
},
N = function() {
c.log("disconnect");
f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.CONNECTION_LOST
})
},
K = function() {
c.log("token lost");
a.player.isPaused && f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.TOKEN_LOST
})
},
P = function() {
c.log("error")
},
Q = function() {
b.get(function(b) {
b === null ? f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.SESSION_LOST
}) : a.connect(b)
}, function() {
a.connect("")
})
},
A = function() {
a.migrateToIndexedDBStorage(function() {}, function() {})
},
R = function() {
f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.NO_SOUND_CAPABILITIES
})
},
W = function() {
f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.WAIT_FOR_COMMERCIAL_TO_FINISH
})
},
X = function() {
G = setTimeout(function() {
f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.CONNECTING
})
}, 1500);
a.player.bind("INVALID_TRACK_URI", function(a) {
a.params.code !== Spotify.Errors.Codes.TRACK_REQUEST_RATE_LIMITED && a.params.domain !== Spotify.Errors.Domains.TRACK_ERROR && f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.TRACK_NOT_PLAYABLE,
trackUri: a.params.trackUri,
response: a.params.response
})
}, this)
},
Y = function() {
a && a.dispose()
},
Z = function(a, b, c) {
var d;
try {
d = JSON.parse(c)
} catch (f) {}
switch (b) {
case "welcome":
a = function(a) {
return function(b) {
z.processFbResponse(a, b)
}
};
if (!d) break;
switch (d.name) {
case "nux_started":
i.disable();
break;
case "nux_complete":
z.setCompleted();
i.enable();
break;
case "get_fb_friends":
t.getFriendsUsingApp(a(d.name));
break;
case "get_fb_friends_without_spotify":
t.getFriendsNotUsingApp(a(d.name));
break;
case "send_fb_inbox_message":
t.sendInboxMessages(d.args, a(d.name));
break
}
case "context-actions":
case "share":
d && d.type == "WINDOW_BLUR" && m.closeAll()
}
},
U = !1,
V = function() {
U || (f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.FLASH_NOT_AVAILABLE
}), U = !0)
},
S = function() {
t = new Spotify.Web.Fb(f, g, v);
t.connect(d.settings.facebookJSSDKConfig, function() {
music = new Spotify.Web.MusicBridge(f, t, C, a);
music.start();
x = new Spotify.Web.OpenGraph(t, a, F);
x.start();
B || (B = new Spotify.Web.Upsell({}, a.user, E), B.onFbConnect(t))
}, function() {
window.setTimeout(S, 3E5);
B || (B = new Spotify.Web.Upsell({}, a.user, E), B.init())
})
},
aa = function(a) {
I.push(a.params);
T()
},
T = function() {
try {
for (var b = 0, c = I.length; b < c; b += 1) a.logging.logger.logJSExceptions(I[b].module, I[b].message, I[b].url, I[b].lineNumber);
I = []
} catch (d) {}
};
h.initialize = function(h, n) {
if (h.needsToAcceptEULA === !0) window.location = "/legal/";
v = n;
F = new Spotify.Web.Exceptions(window);
F.bind(Spotify.Web.ErrorTypes.UNCAUGHT_EXCEPTION, aa, this);
F.bindWindow(window, "global");
Spotify.Web.BrowserDetect.init();
if (!h) throw Error("Server-side settings not provided");
d.settings = h;
c = new Spotify.Web.Logger;
f = new Spotify.Web.Publisher;
f.subscribe(Spotify.Web.PublisherMessages.APPLICATION_STATE_PUSH, this);
f.subscribe(Spotify.Web.PublisherMessages.APPLICATION_OPEN_URI, this);
f.subscribe(Spotify.Web.PublisherMessages.APPLICATION_CLOSED, this);
f.subscribe(Spotify.Web.PublisherMessages.FB_APP_UNKNOWN, this);
f.subscribe(Spotify.Web.PublisherMessages.FB_APP_CONNECTED, this);
f.subscribe(Spotify.Web.PublisherMessages.FB_APP_NOT_AUTHENTICATED, this);
f.subscribe(Spotify.Web.PublisherMessages.FB_CONNECTION_FAILURE, this);
f.subscribe(Spotify.Web.PublisherMessages.USER_AUTHENTICATION_FAILURE, this);
f.subscribe(Spotify.Web.PublisherMessages.APPLICATION_VERSION_CHANGED, this);
f.subscribe(Spotify.Web.PublisherMessages.APPLICATION_POST_MESSAGE, this);
f.subscribe(Spotify.Web.PublisherMessages.SUGGEST_SHOW, this);
f.subscribe(Spotify.Web.PublisherMessages.SUGGEST_HIDE, this);
window.addEventListener("message", function(a) {
f.notify(Spotify.Web.PublisherMessages.APPLICATION_POST_MESSAGE, {
url: Spotify.Web.Utils.appNameFromUrl(a.origin),
name: Spotify.Web.Utils.appNameFromUrl(a.origin),
data: a.data
})
}, !1);
b = new Spotify.Web.Credentials("/xhr/json/auth.php");
d.settings.credentials && b.cache(d.settings.credentials[0], d.settings.credentials[1]);
var w, t, B = Spotify.Web.FeatureDetect;
w = B.getFlashVersion();
t = Spotify.Web.BrowserDetect.browser;
var x = Spotify.Web.BrowserDetect.version,
y = Spotify.Web.BrowserDetect.OS;
w = w.major >= 11 && w.minor >= 3 && t === "Explorer" && x >= 10 || (y === "Windows" || y === "Linux") && t !== "Explorer" || t === "Chrome" && (y === "Windows" || y === "Linux") || t === "Safari" && x >= 6 || y === "Mac" && (navigator.userAgent.indexOf("10.8") > -1 || navigator.userAgent.indexOf("10_8") > -1) || t === "Firefox" && x >= 11 && (y === "Windows" || y === "Linux");
window.location.href.indexOf("websockets") > -1 || w ? (w = Spotify.GatewayTypes.WEBSOCKETS, t = d.settings.aps.ws) : (w = Spotify.GatewayTypes.FLASH, t = d.settings.aps.rtmp);
if ((x = Spotify.Web.URLParser.parseURL(location.href)) && x.params) x = x.params, typeof x.ap !== "undefined" && (w = x.ap.indexOf("rtmp") === 0 ? Spotify.GatewayTypes.FLASH : Spotify.GatewayTypes.WEBSOCKETS, t = x.ap.replace(/\\/g, ""));
d.settings.connectionUri = t instanceof Array ? t.join("|") : t;
t = Spotify.PlayerTypes.FLASH_HTTP;
if (Spotify.Web.BrowserDetect.browser === "Explorer") x = Math.floor(Math.random() * 1E3), d.settings.SWFUrl += "?rnd=" + x, d.settings.protoSchemasLocationRandomizer = "?rnd=" + x;
a = new Spotify.Core(w, t, d.settings);
a.onReady = X;
a.onError = P;
a.onConnect = L;
a.onDisconnect = N;
a.onTokenLost = K;
a.bind("ON_TRY_TO_CONNECT", Q, this);
a.bind("NO_SOUND_CAPABILITIES", R, this);
a.bind("STORAGE_FULL", A, this);
a.bind("WAIT_FOR_COMMERCIAL_TO_FINISH", W, this);
a.bind("FLASH_UNAVAILABLE", V, this);
a.initialize();
o = new Spotify.Web.StateHistory.Manager({
sections: [{
link: Spotify.Link.applicationLink("home"),
type: "section"
}, {
link: Spotify.Link.applicationLink("radio"),
type: "section",
persistent: !0
}, {
link: Spotify.Link.applicationLink("playlist"),
type: "section"
}, {
link: Spotify.Link.applicationLink("welcome"),
type: "section"
}, {
link: Spotify.Link.applicationLink("user"),
type: "section"
}, {
link: Spotify.Link.applicationLink("suggest"),
type: "popup"
}, {
link: Spotify.Link.applicationLink("context-actions"),
type: "popup"
}, {
link: Spotify.Link.applicationLink("about"),
type: "section"
}]
});
o.initialize();
k = new Spotify.Web.Router(o, d);
q = new Spotify.Web.AppManager(o, k.getAppUrl, document);
s = new Spotify.Web.View(o, q, document.getElementById("main"));
s.bind("onFrontPaneUpdate", function(a) {
a.params.node.focus()
});
i = new Spotify.Web.Menu({
publisher: f,
elements: document.getElementById("main-nav").querySelectorAll("ul span"),
defaultId: d.defaultState.id
});
i.initialize();
document.getElementById("main-nav").addEventListener("click", function(a) {
a.target.id === "main-nav" && (o.isRootActive() || o.moveViewport(-1))
});
i.bind("onAppOpen", function(a) {
k.openUri(Spotify.Link.fromString("spotify:app:" + a.params.id).toAppLink())
});
q.bind("onFrameCreated", function(a) {
f.notify(Spotify.Web.PublisherMessages.APPLICATION_STATE_CHANGED, {
link: a.params.app.link,
iframe: a.params.node
})
});
q.bind("onFrameUpdated", function(a) {
f.notify(Spotify.Web.PublisherMessages.APPLICATION_STATE_CHANGED, {
link: a.params.app.link,
iframe: a.params.node
})
});
q.bind("onFrameDisposed", function(a) {
f.notify(Spotify.Web.PublisherMessages.APPLICATION_DISPOSED, {
link: a.params.app.link,
iframe: a.params.node
})
});
o.bind("doCommand", function(a) {
a = a.params.command;
a.type === Spotify.Web.StateHistory.CommandTypes.SHOW_SECTION && i.highlightMenu(a.section.id)
});
o.bind("onPopup", function(a) {
var b = a.params.link.id,
c = a.params.origin;
b === "suggest" && (l.isVisible() ? f.notify(Spotify.Web.PublisherMessages.SUGGEST_HIDE) : f.notify(Spotify.Web.PublisherMessages.SUGGEST_SHOW));
(b === "context-actions" || b === "share") && m.popup(a.params.link, c)
});
p = new Spotify.Web.Router.History(o, History);
p.bind("pageChange", function(a) {
E.pageView("/" + Spotify.Web.URLParser.parseURL(a.params.url).path);
m.closeAll()
});
o.bind("onBrowserHistoryPush", function(a) {
p.push(a.params.link)
});
o.bind("onBrowserHistoryReplace", function(a) {
p.replace(a.params.link)
});
u = new Spotify.Web.Error({
publisher: f,
element: document.getElementById("notification-area"),
dialog: document.getElementById("modal-notification-area"),
timeout: 4E3
});
u.initialize();
M = new Spotify.Web.ScrollBlocker(document.getElementById("sb"), f);
M.init();
(t === Spotify.PlayerTypes.FLASH_HTTP || w === Spotify.GatewayTypes.FLASH) && window.addEvent("load", function() {
Spotify.Web.FeatureDetect.hasFlashMin() || window.setTimeout(function() {
V()
}, 1E3)
});
O();
m = new Spotify.Web.PopupManager(k, f, document.getElementById("wrapper"));
m.registerPopup("context-actions", {
preventScrolling: !0,
hideOnWindowResize: !0
});
l = new Spotify.Web.PopupWindow({
url: k.getAppUrl("/suggest/"),
id: "suggest",
wrapper: document.getElementById("suggest-area"),
iframe: document.getElementById("suggest"),
hideMessage: Spotify.Web.PublisherMessages.SUGGEST_HIDDEN,
showMessage: Spotify.Web.PublisherMessages.SUGGEST_SHOWN,
postHideCallback: function() {
document.activeElement.blur();
q.getActiveFrame().focus()
}
}, f);
g = new Spotify.Web.Static;
if (d.settings.preload && d.settings.preload.length) for (w = 0; w < d.settings.preload.length; w++) g.preloadImage(d.settings.preload[w]);
E = new Spotify.Web.Tracking(f, g, d.settings.tracking);
E.initialize();
F.addHandler(E.handleException);
B.adBlockCheck() && f.notify(Spotify.Web.PublisherMessages.ERROR, {
type: Spotify.Web.ErrorTypes.AD_BLOCK_DETECTED
});
f.notify(Spotify.Web.PublisherMessages.CHROME_READY);
z = new Spotify.Web.NUX(o, q, k.getAppUrl)
};
h.onNotify = function(b) {
var c = b.message,
d = Spotify.Web.PublisherMessages;
switch (b.messageType) {
case d.APPLICATION_POST_MESSAGE:
Z(c.url, c.name, c.data);
break;
case d.APPLICATION_OPEN_URI:
i.enable();
k.openUri(c.link, c.origin, c.replace);
break;
case d.APPLICATION_VERSION_CHANGED:
f.notify(d.ERROR, {
type: Spotify.Web.ErrorTypes.APPLICATION_RELOAD_NEEDED
});
break;
case d.SUGGEST_SHOW:
l.show();
break;
case d.SUGGEST_HIDE:
l.hide();
break;
case d.APPLICATION_CLOSED:
b = a.player.trackUri, b.indexOf("spotify:ad:") > -1 && a.adChooser.recordAdEvent(b, "attempt")
}
};
h.GdpSuccess = function() {};
h.GdpError = function() {};
h.GdpDeny = function() {};
return h
}();
Spotify.Web.GDP = function(d) {
function h(a) {
if (a.status === "connected") {
var c = a.authResponse.userID,
a = a.authResponse.accessToken;
b.notify(Spotify.Web.PublisherMessages.FB_APP_CONNECTED, {
userID: c,
accessToken: a
});
f.hide();
(new Request({
url: "/xhr/json/gdp/create.php",
method: "get",
data: {
fbuid: c,
access_token: a
},
onSuccess: i
})).send()
}
}
var f = this,
b = d.publisher,
c = d.fbBridge,
a, g = new Spotify.Web.GDP.View({
player: d.core.player
});
this.initialize = function() {
a = c.getAPI();
b.subscribe(Spotify.Web.PublisherMessages.FB_APP_CONNECTED, f);
b.subscribe(Spotify.Web.PublisherMessages.FB_APP_NOT_AUTHENTICATED, f);
a.Event.subscribe("auth.statusChange", h)
};
this.createDialog = function() {
g.initialize(null, f.show)
};
this.show = function() {
g.show()
};
this.hide = function() {
g.hide()
};
this.error = function() {
g.render(g.templates.ERROR)
};
this.deny = function() {
g.render(g.templates.CANCEL)
};
this.authenticate = function() {
c.getLoginStatus()
};
this.onNotify = function(a) {
var c = Spotify.Web.PublisherMessages;
switch (a.messageType) {
case c.APPLICATION_ENABLED:
setupTrack();
break;
case c.FB_APP_NOT_AUTHENTICATED:
b.unsubscribe(Spotify.Web.PublisherMessages.FB_APP_CONNECTED, f);
break;
case c.FB_APP_CONNECTED:
window.location.href = "/login/?forward=" + encodeURIComponent("/welcome/")
}
};
var i = function(a) {
a = JSON.parse(a);
a.status === "success" ? b.notify(Spotify.Web.PublisherMessages.USER_AUTHENTICATED) : b.notify(Spotify.Web.PublisherMessages.USER_AUTHENTICATION_FAILURE, a)
}
};
Spotify.Web.GDP = Spotify.Web.GDP || {};
Spotify.Web.GDP.View = function() {
function d(a, d) {
var f = c[a];
f ? (b.node.innerHTML = f, typeof d === "function" && d.call(this, f)) : (new Request({
url: a,
method: "get",
onSuccess: function(f) {
c[a] = f;
b.node.innerHTML = f;
typeof d === "function" && d.call(this, f)
}
})).send()
}
function h() {
document.getElementById("retry-button").addEventListener("click", function() {
b.render(b.templates.MAIN)
})
}
function f() {
var a = document.createElement("div");
a.id = "gdp-container";
a.classList.add("modal-notification");
document.body.appendChild(a);
return a
}
var b = this,
c = {};
this.player = this.node = null;
this.templates = {
MAIN: "/static/templates/gdp-main.html",
ERROR: "/static/templates/gdp-error.html",
CANCEL: "/static/templates/gdp-cancel.html"
};
this.initialize = function(a, c) {
b.node = b.node || f();
this.render(this.templates.MAIN, function() {
typeof c === "function" && c.call(this)
})
};
this.render = function(a, b) {
var c;
switch (a) {
case this.templates.ERROR:
c = h;
break;
case this.templates.CANCEL:
c = h;
break;
default:
c = b
}
d(a, c)
};
this.show = function() {
b.node.style.display = "block"
};
this.hide = function() {
b.node.style.display = "none"
}
};
Spotify.Web.Utils = function() {
var d = {},
h = RegExp("(?:user/(.*)/)?(home|starred|welcome|radio|track|artist|album|playlist|search|debug|user|test-runner)/?(.*)?/?");
d.spotifyUriToOrigin = function(d) {
var d = d.split(":"),
b = d[1],
c = d[2];
b === "user" && d[3] === "playlist" && (b = "playlist", c += ":" + d[4]);
return "spotify:app:" + b + ":" + c
};
d.spotifyUriToFullAppPath = function(d, b) {
var c = d.split(":"),
a = c[1];
a === "user" && c[3] === "playlist" && (a = "playlist");
return b(a)
};
d.spotifyUriToOpenUrl = function(d, b) {
if (d) {
for (var c = d.split(":"), a = b || "http://open.spotify.com", g = 1; g < c.length; g++) {
if (c[g] === "top") break;
a += "/" + c[g]
}
return a
} else
return ""
};
d.decodeOpenGraphUrl = function(d) {
d = d.replace("#_=_", "");
if (d = d.match(h)) {
var b = d[3] || null;
b !== null && (b = b.replace(/\//g, ":"), b = b[b.length - 1] === ":" ? b.slice(0, -1) : b);
return {
user: d[1] || null,
context: d[2] || null,
contextId: b
}
} else
return null
};
d.openGraphUrlToSpotifyUri = function(f) {
if (!f) return null;
var b = d.decodeOpenGraphUrl(f);
if (!b) return "";
b.user ? f = b.contextId ? "spotify:user:" + b.user + ":" + b.context + ":" + b.contextId : "spotify:user:" + b.user + ":" + b.context : b.contextId ? b.context === "search" ? (f = f.replace("#_=_", "").replace(/\/$/, "").split("/"), f.splice(0, 3), f.unshift("https://play.spotify.com/app"), f = f.join("/"), f = Spotify.Link.fromString(f).toURI()) : f = "spotify:" + b.context + ":" + b.contextId : f = "spotify:app:" + b.context;
return f
};
d.addTransitionEndedListener = function(d, b, c) {
var a = !1,
g = function(c) {
a = !0;
b(c);
h()
},
h = function() {
d.removeEventListener("webkitTransitionEnd", g, !1);
d.removeEventListener("transitionend", g, !1);
d.removeEventListener("msTransitionEnd", g, !1);
d.removeEventListener("oTransitionEnd", g, !1)
};
d.addEventListener("webkitTransitionEnd", g, !1);
d.addEventListener("transitionend", g, !1);
d.addEventListener("msTransitionEnd", g, !1);
d.addEventListener("oTransitionEnd", g, !1);
setTimeout(function() {
a || h()
}, c || 2E3)
};
d.getWindowPosition = function(d) {
var b = 0,
c = 0;
do b += d.offsetLeft, c += d.offsetTop;
while (d = d.offsetParent);
return {
left: b,
top: c
}
};
d.appNameFromUrl = function(d) {
return (d = d.match(/^https?:\/\/[A-Za-z0-9]{40}-([A-Za-z0-9_-]+).*/)) ? d[1] : null
};
return d
}();
Spotify.Web.Fb = function(d, h, f) {
var b = this,
c = f || null,
a = Spotify.Web.PublisherMessages,
g = 50,
i = function(a, b, d) {
c = c || window.FB;
c.init({
appId: a.appId,
music: "music" in a ? a.music : !1,
cookie: "cookie" in a ? a.cookie : !0,
logging: "logging" in a ? a.logging : !0,
status: "status" in a ? a.status : !1,
xfbml: "xfbml" in a ? a.xfbml : !1,
oauth: "oauth" in a ? a.oauth : !1
});
n(b, d)
},
n = function(b, f) {
c.getLoginStatus(function(c) {
switch (c.status) {
case "connected":
d.notify(a.FB_APP_CONNECTED);
b();
break;
case "not_authorized":
f();
break;
default:
f()
}
}, !0)
},
l = function(a, c) {
var d = b.getApi(),
f = "[" + a.join(",") + "]";
d.api("/threads", "post", {
to: f,
name: "Hey, sign up for a free Spotify account and come check out my music!",
link: "http://www.spotify.com/start/?ref=linknuxinv"
}, c)
},
m = function(a) {
var b = {
status: "failure",
message: ""
};
typeof a.error_msg != "undefined" ? b.message = a.error_msg : (b.status = "success", b.message = a);
return b
};
this.connect = function(a, b, d) {
if (!a || typeof a.appId !== "string") throw Error("AppId required");
c ? n(b, d) : (h.loadScript("https://connect.facebook.net/en_US/all/vb.js"), window.FB ? i(a, b, d) : window.fbAsyncInit = function() {
i(a, b, d)
})
};
this.getApi = function() {
if (c) return c;
else
throw Error("FB API not initialized");
};
this.getDevices = function(a) {
this.getApi().api("/me?fields=devices", function(b) {
if (typeof a === "function") {
var c = [];
if (typeof b.devices !== "undefined" && b.devices.length > 0) for (var b = b.devices, d = b.length, f = 0; f < d; f++) typeof b[f].hardware !== "undefined" ? c.push(b[f].hardware.toLowerCase()) : typeof b[f].os !== "undefined" && c.push(b[f].os.toLowerCase());
a.call(this, c)
}
})
};
this.getFriendsUsingApp = function(a) {
this.getApi().api({
method: "fql.query",
query: "SELECT uid, name FROM user WHERE is_app_user = 1 AND uid IN (SELECT uid2 FROM friend WHERE uid1 = me())"
}, function(b) {
b = m(b);
typeof a === "function" && a.call(this, b)
})
};
this.getFriendsNotUsingApp = function(a) {
this.getApi().api({
method: "fql.query",
query: "SELECT uid, name FROM user WHERE is_app_user = 0 AND uid IN (SELECT uid2 FROM friend WHERE uid1 = me())"
}, function(b) {
b = m(b);
typeof a === "function" && a.call(this, b)
})
};
this.getUserImage =
function(a) {
this.getApi().api({
method: "fql.query",
query: "select id, width, height, url, is_silhouette, real_width, real_height from profile_pic where id=me()"
}, function(b) {
b = m(b);
typeof a === "function" && a.call(this, b)
})
};
this.getUsersName = function(a) {
this.getApi().api("/me?fields=name,last_name,first_name", function(b) {
b = m(b);
typeof a === "function" && a.call(this, b)
})
};
this.sendInboxMessages = function(a, b) {
function c(d) {
a.length > 0 ? l(a.splice(0, g), c) : (d = m(d), typeof b === "function" && b.call(this, d))
}
a.length > 0 && l(a.splice(0, g), c)
}
};
Spotify.Web.Context = function(d) {
this.getState = function() {
return d.getState()
};
this.getContext = function() {
return d.getState().context
};
this.getFacebookContextType = function() {
var d = this.getContext();
if (!d || !d.uri) return null;
var f = null;
switch (d.uri.split(":")[1]) {
case "user":
f = "playlist";
break;
case "album":
f = "album";
break;
case "artist":
f = "musician";
break;
case "radio":
f = "radio_station"
}
return f
};
this.getContextUrl = function() {
var d = this.getContext();
return d ? Spotify.Web.Utils.spotifyUriToOpenUrl(d.uri) : null
};
this.addEventListener = function(h, f) {
d.addEvent(h, f)
}
};
Spotify.Web.FacebookURLSchema = function() {
var d = function(d) {
var f = {};
if (d.song) f.trackUrl = decodeURIComponent(d.song);
if (d.musician) f.contextUrl = decodeURIComponent(d.musician);
else if (d.album) f.contextUrl = decodeURIComponent(d.album);
else if (d.playlist) f.contextUrl = decodeURIComponent(d.playlist);
return f
};
this.shouldPlay = function(d) {
d = Spotify.Web.URLParser.parseURL(d).params;
return !(!d || !d.song && !d.musician && !d.album && !d.playlist)
};
this.getUrl = function(h) {
var f = Spotify.Web.URLParser.parseURL(h, !0);
if (!f.path) f.path = "";
if (this.shouldPlay(h)) {
h = Spotify.Web.URLParser.parseURL(h).params;
h = d(h);
if (!h.contextUrl && h.trackUrl) h.contextUrl = h.trackUrl, h.trackUrl = void 0;
if (h.contextUrl) h = Spotify.Web.Utils.decodeOpenGraphUrl(h.contextUrl), f.path = "", h.user && (f.path += "user/" + h.user + "/"), f.path += h.context + "/" + h.contextId
}
return f.protocol + "://" + f.domain + "/" + f.path
};
this.playUrl = function(h, f, b, c) {
if (this.shouldPlay(h)) {
h = Spotify.Web.URLParser.parseURL(h).params;
h = d(h);
if (!h.contextUrl && h.trackUrl) h.contextUrl = h.trackUrl, h.trackUrl =
void 0;
if (h.contextUrl) {
var a = Spotify.Web.Utils.openGraphUrlToSpotifyUri(h.contextUrl),
g;
if (h.trackUrl) g = Spotify.Web.Utils.decodeOpenGraphUrl(h.trackUrl).contextId;
Spotify.Web.Utils.decodeOpenGraphUrl(h.contextUrl).context === "artist" && g && (a = Spotify.Web.Utils.openGraphUrlToSpotifyUri(h.trackUrl), g = void 0);
f(a, g, b, c);
return !0
}
} else
return !1
}
};
Spotify.Web.OpenURLSchema = function() {
var d = /\/(?:user)?\/?(\w*)?\/?(playlist|album|artist|track)\/(\w{22})(?:\?play=)?(true|\w{22})?/,
h = function(f) {
return (f = f.match(d)) ? {
user: f[1] || null,
context: f[2] || null,
contextId: f[3] || null,
play: f[4] || null
} : null
};
this.shouldPlay = function(d) {
d = h(d);
return !(!d || !d.context || !(d.context === "track" || d.play))
};
this.getUrl = function(d) {
d = Spotify.Web.URLParser.parseURL(d, !0);
if (!d.path) d.path = "";
return d.protocol + "://" + d.domain + "/" + d.path
};
this.playUrl = function(d, b, c, a) {
if (this.shouldPlay(d)) {
var d =
h(d),
g = "spotify:";
d.user && (g += "user:" + d.user + ":");
g += d.context + ":" + d.contextId;
var i;
if (d.play !== "true") i = d.play;
d.context === "artist" && i && (g = "spotify:track:" + i, i = void 0);
b(g, i, c, a);
return !0
} else
return !1
}
};
Spotify.Web.OpenGraph = function(d, h, f) {
var b = h.player,
c = new Spotify.Web.Context(h.contextPlayer),
a = d.getApi().getAccessToken(),
g = new Spotify.Events,
i, n = function(b, c, d) {
b = "https://graph.facebook.com/me/music.listens?song=" + b;
c && (b += "&" + c + "=" + d);
b += "&access_token=" + a;
(new Request.CORS({
url: b,
data: null,
method: "post",
onSuccess: function(a) {
JSON.parse(a)
},
onFailure: function(a) {
f.logError("web.fb.opengraph.js", a.statusText, a.responseText)
}
})).send()
},
l = function(a, b, c) {
i && clearTimeout(i);
i = setTimeout(function() {
n(a, b, c);
clearTimeout(i)
}, 15E3)
},
m = function() {
if (!(b.trackUri.indexOf(":ad:") > -1)) {
var a = Spotify.Web.Utils.spotifyUriToOpenUrl(b.trackUri),
d = c.getFacebookContextType(),
f = c.getContextUrl();
l(a, d, f)
}
},
o = function() {
i && clearTimeout(i)
},
k = function() {
i && clearTimeout(i)
};
this.start = function() {
b.bind(g.PLAYING, m);
b.bind(g.PAUSED, o);
b.bind(g.STOPPED, k)
}
};
Spotify.Web.MusicBridge = function(d, h, f, b) {
Spotify.Web.Context.call(this, b);
var c = b.player,
a = new Spotify.Web.Context(b.contextPlayer),
g, i = new Spotify.Events,
n = function(a) {
var b;
if (a.album) b = a.album;
else if (a.playlist) b = a.playlist;
else if (a.song) b = a.song;
else if (a.musician) b = a.musician;
if (b) {
b = Spotify.Web.Utils.decodeOpenGraphUrl(b);
var c;
c = b.user ? "spotify:user:" + b.user + ":" + b.context + ":" + b.contextId : "spotify:" + b.context + ":" + b.contextId;
b.context === "artist" && (c += ":top:tracks");
var d;
if (b.context !== "track" && a.song) d = Spotify.Web.Utils.decodeOpenGraphUrl(a.song).contextId;
f.play(c, d)
}
},
l = function() {
f.resume()
},
m = function() {
f.pause()
},
o = function(b) {
var b = b || c.isPlaying,
b = {
playing: b,
song: Spotify.Web.Utils.spotifyUriToOpenUrl(c.trackUri, "https://play.spotify.com"),
user_id: g.getUserID()
},
d = a.getFacebookContextType();
d && (b[d] = a.getContextUrl());
g.Music.send("STATUS", b)
},
k = function() {
o()
},
p = function() {
o(!0)
},
q = function() {
o(!1)
},
s = function() {
o(!1)
};
this.start = function() {
g = h.getApi();
g.Event.subscribe("fb.music.PLAY", n);
g.Event.subscribe("fb.music.RESUME", l);
g.Event.subscribe("fb.music.PAUSE", m);
g.Event.subscribe("fb.music.STATUS", k);
g.Event.subscribe("fb.music.BRIDGE_READY", function() {});
g.Event.subscribe("fb.music.ALREADY_CONNECTED", function() {});
g.Event.subscribe("fb.music.USER_MISMATCH", function() {});
c.bind(i.PLAYING, p);
c.bind(i.PAUSED, q);
c.bind(i.STOPPED, s);
d.subscribe(Spotify.Web.PublisherMessages.APPLICATION_CLOSED, this)
};
this.onNotify = function(a) {
a.messageType === Spotify.Web.PublisherMessages.APPLICATION_CLOSED && (a = {
offline: !0,
user_id: g.getUserID()
}, g.Music.send("STATUS", a))
}
};
Spotify.Web.NUX = function(d, h, f) {
function b(b) {
var k;
b.response || n();
parseInt(b.response.ab_test_group, 10) > l && b.response.link_tutorial_completed == g ? (b = "", b = Spotify.Web.URLParser.parseURL(redirectTo), k = (b = b.pathSegments && b.pathSegments[0] === a.resourceId ? b.pathSegments.slice(1).join(":") : b.path) ? [b.replace(/\//g, ":")] : "", b = k, d.openUri(Spotify.Link.fromString("spotify:app:" + a.resourceId + ":" + b).toAppLink())) : n()
}
function c() {
n()
}
var a = this;
this.resourceId = "welcome";
f(this.resourceId);
var g = "0",
i, n, l = 333;
this.processFbResponse = function(b, c) {
c.name = b;
try {
var f = JSON.stringify(c)
} catch (g) {
return
}
var i = h.getActiveFrame();
d.getCurrentLink().id === a.resourceId && i.contentWindow.postMessage(f, "*")
};
this.setCompleted = function() {
(new Request({
url: "/xhr/json/nux/complete.php",
method: "get",
onSuccess: function() {}
})).send()
};
this.init = function(a, d, f) {
i = a;
redirectTo = d;
n = f;
i.onReady(function() {
i.getUserInfo(b, c)
}, this)
}
};
Spotify.Web.Ads = {};
Spotify.Web.Ads.PixelTracker = function(d) {
this.core = d
};
Spotify.Web.Ads.PixelTracker.prototype.init = function() {
img = document.createElement("img");
img.id = "tpx";
document.getElementById("main-nav").appendChild(img);
context = new Spotify.Web.Context(this.core.contextPlayer);
context.addEventListener("play", this.onTrackAboutToBePlayed)
};
Spotify.Web.Ads.PixelTracker.prototype.onTrackAboutToBePlayed = function() {
var d = context.getState().track;
d && d.advertisement && typeof d.popularity === "string" && d.popularity.match(/^https/) && setTimeout(function() {
img.src = d.popularity
}, 10)
};
Spotify.Web.Upsell = function(d, h, f) {
var b = this,
d = d || {},
c = d.onBeforeTimeout || 500,
a = d.loggingEnabled || !0,
g = d.controlGroup || 166,
i = null,
n = !1;
this.simulation = !1;
var l = document.getElementById("desktop"),
m = null,
o = null,
k = null;
this.init = function() {
var a = this.getDisplayMode();
a && this.applyDisplayMode(a)
};
var d = function(a) {
window.location = a.downloadLink
},
p = function() {
var a = m.querySelector('input[name="phone_number"]'),
b = m.querySelector('button[class="sp-button"]'),
c = m.querySelector(".error");
/^\d{7,}$/.test(a.value.replace(/[\s()+\-\.]|ext/gi, "")) ? (a.setAttribute("disabled", "disabled"), b.setAttribute("disabled", "disabled"), c.innerHTML = "", (new Request({
url: "/xhr/json/sms/send_sms.php",
method: "get",
data: {
phone_number: a.value
},
onSuccess: function(d) {
try {
d = JSON.parse(d)
} catch (f) {
d = {}
}
if (typeof d.status !== "undefined" && d.status) m.querySelector(".phone-input").style.display = "none", $(m.querySelector(".success-feedback")).addClass("show"), x("send_sms");
else {
var g = "An unexpected error occurred when sending the SMS";
if (typeof d.message !== "undefined") g =
d.message;
c.innerHTML = g;
a.removeAttribute("disabled");
b.removeAttribute("disabled")
}
},
onError: function() {
c.innerHTML = "An unexpected error occurred when sending the SMS";
a.removeAttribute("disabled");
b.removeAttribute("disabled")
}
})).send()) : c.innerHTML = "The phone number is invalid"
},
q = {
android: {
id: "send-sms-android",
label: "android",
text: "Get Spotify",
subText: "on your Android",
buttonText: "Get Started",
mainClass: "android",
options: {
actions: {
".sp-button": p
}
}
},
iphone: {
id: "send-sms-iphone",
label: "iphone",
text: "Get Spotify",
subText: "on your iPhone",
buttonText: "Get Started",
mainClass: "iphone",
options: {
actions: {
".sp-button": p
}
}
},
windows: {
id: "download-dialog-windows",
label: "windows",
text: "Install Spotify on Windows",
subText: "For the full Spotify experience",
buttonText: "Install Spotify",
downloadLink: "http://download.spotify.com/Spotify%20Installer.exe",
mainClass: "desktop-background",
options: {},
onBefore: d
},
mac: {
id: "download-dialog-mac",
label: "mac",
text: "Install Spotify on Your Mac",
subText: "For the full Spotify experience",
buttonText: "Install Spotify",
downloadLink: "http://download.spotify.com/Spotify.dmg",
mainClass: "desktop-background",
options: {},
onBefore: d
}
};
this.getDisplayMode = function(a, b) {
var c = null;
typeof a !== "undefined" ? typeof b !== "undefined" && b.getDevices(function(b) {
var d;
if (b.length > 0) {
if (d = null, b.length > 0) {
var f = null;
b.indexOf("iphone") >= 0 ? f = "iphone" : b.indexOf("android") >= 0 ? f = "android" : b.indexOf("ipad") >= 0 && (f = "ipad");
b = f;
b !== null && typeof q[b] !== "undefined" && (d = q[b])
}
} else d = y();
c = d;
a(c)
}) : c = y();
return c
};
this.isEnabled = function() {
return i == null || i >= g || this.simulation
};
this.applyDisplayMode = function(a) {
if (h !== null) h.onReady(function() {
h.getUserInfo(function(c) {
c.response && (i = parseInt(c.response.ab_test_group, 10));
b.setDisplayMode(a)
})
}, this)
};
this.onFbConnect = function(a) {
this.getDisplayMode(function(a) {
b.applyDisplayMode(a)
}, a)
};
this.showPopup = function(a) {
if (!n) k = document.getElementById("download-spotify"), m = document.getElementById(a.id), m.style.display = "block", o = m.querySelector(".dialog"), t(o, k), o.className += " show", n = !0, window.addEventListener("resize", s, !1), window.addEventListener("keydown", u), m.addEventListener("click", C)
};
this.hidePopup = function() {
if (n) {
var a = m.querySelector(".dialog");
$(a).removeClass("show");
m.style.display = "none";
n = !1;
window.removeEventListener && (window.removeEventListener("resize", s), window.removeEventListener("keydown", u), m.removeEventListener("click", C))
}
};
this.setDisplayMode = function(a) {
if (a && this.isEnabled()) {
l.querySelector(".title").innerHTML = a.text;
l.querySelector(".subtitle").innerHTML =
a.subText;
l.querySelector("button").querySelector(".sp-button-text").innerHTML = a.buttonText;
if (typeof a.mainClass !== "undefined") {
var c = l.querySelector(".content");
c.className = "content";
$(c).addClass("upsell-background");
$(c).addClass(a.mainClass)
}
w(a);
v(a);
this.fixHeight();
window.addEventListener("resize", b.fixHeight, !1);
l.querySelector(".content").addClass("show");
x("show_version", a.label)
}
};
this.simulate = function(a) {
if (typeof q[a] !== "undefined") this.simulation = !0, this.setDisplayMode(q[a])
};
this.fixHeight =
function() {
var a = l.parentNode;
l.style.height = a.offsetHeight - a.querySelector("#app-player").offsetHeight + "px"
};
var s = function() {
t(o, k)
},
u = function(a) {
a.keyCode == 27 && b.hidePopup()
},
w = function(a) {
l.querySelector("#download-spotify").onclick = function() {
typeof a.onBefore !== "undefined" ? (b.showPopup(a), window.setTimeout(function() {
a.onBefore(a)
}, c)) : b.showPopup(a);
x("click_version")
}
},
v = function(a) {
if (typeof a.options.actions !== "undefined") for (action in a.options.actions) if (a.options.actions.hasOwnProperty(action)) document.querySelector("#" + a.id + " " + action).onclick = function() {
a.options.actions[action]()
}
},
t = function(a, b) {
var c = $(b).getSize().y / 2,
d = $(b).getPosition(),
c = {
x: d.x - (a.getSize().x + 15),
y: d.y - a.getSize().y * 0.7 + c
};
$(a).position(c)
},
y = function() {
var a = null,
b = Spotify.Web.BrowserDetect.OS.toLowerCase();
typeof q[b] !== "undefined" && (a = q[b]);
return a
},
C = function(a) {
n && (!a.target || !$(a.target).getParents().contains(m)) && b.hidePopup()
},
x = function(b, c) {
a && f && f.event("upsell", b, c || "", 1)
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment