Created
November 17, 2012 00:41
-
-
Save vr000m/4092220 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
History.js Native Adapter | |
@author Benjamin Arthur Lupton <[email protected]> | |
@copyright 2010-2011 Benjamin Arthur Lupton <[email protected]> | |
@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 <[email protected]> | |
@author James Padolsey <https://gist.github.com/527683> | |
History.isInternetExplorer() | |
Are we using Internet Explorer? | |
@return {boolean} | |
@license Public Domain | |
@author Benjamin Arthur Lupton <[email protected]> | |
History.js Core | |
@author Benjamin Arthur Lupton <[email protected]> | |
@copyright 2010-2011 Benjamin Arthur Lupton <[email protected]> | |
@license New BSD License <http://creativecommons.org/licenses/BSD/> | |
History.js HTML4 Support | |
Depends on the HTML5 Support | |
@author Benjamin Arthur Lupton <[email protected]> | |
@copyright 2010-2011 Benjamin Arthur Lupton <[email protected]> | |
@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("<", "<").replace(">", ">").replace(" & ", " & ") | |
} 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