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 <contact@balupton.com> | |
| @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com> | |
| @license New BSD License <http://creativecommons.org/licenses/BSD/> | |
| History.getInternetExplorerMajorVersion() | |
| Get's the major version of Internet Explorer | |
| @return {integer} | |
| @license Public Domain | |
| @author Benjamin Arthur Lupton <contact@balupton.com> | |
| @author James Padolsey <https://gist.github.com/527683> | |
| History.isInternetExplorer() | |
| Are we using Internet Explorer? | |
| @return {boolean} | |
| @license Public Domain | |
| @author Benjamin Arthur Lupton <contact@balupton.com> | |
| History.js Core | |
| @author Benjamin Arthur Lupton <contact@balupton.com> | |
| @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com> | |
| @license New BSD License <http://creativecommons.org/licenses/BSD/> | |
| History.js HTML4 Support | |
| Depends on the HTML5 Support | |
| @author Benjamin Arthur Lupton <contact@balupton.com> | |
| @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com> | |
| @license New BSD License <http://creativecommons.org/licenses/BSD/> | |
| SWFObject v2.2 <http://code.google.com/p/swfobject/> is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>. | |
| */ | |
| (function(d, h) { | |
| var f = d.History = d.History || {}; | |
| if (typeof f.Adapter !== "undefined") throw Error("History.js Adapter has already been loaded..."); | |
| f.Adapter = { | |
| handlers: {}, | |
| _uid: 1, | |
| uid: function(b) { | |
| return b._uid || (b._uid = f.Adapter._uid++) | |
| }, | |
| bind: function(b, c, a) { | |
| var g = f.Adapter.uid(b); | |
| f.Adapter.handlers[g] = f.Adapter.handlers[g] || {}; | |
| f.Adapter.handlers[g][c] = f.Adapter.handlers[g][c] || []; | |
| f.Adapter.handlers[g][c].push(a); | |
| b["on" + c] = function(a, b) { | |
| return function(c) { | |
| f.Adapter.trigger(a, b, c) | |
| } | |
| }(b, c) | |
| }, | |
| trigger: function(b, c, a) { | |
| var a = a || {}, | |
| b = f.Adapter.uid(b), | |
| g, i; | |
| f.Adapter.handlers[b] = f.Adapter.handlers[b] || {}; | |
| f.Adapter.handlers[b][c] = f.Adapter.handlers[b][c] || []; | |
| for (g = 0, i = f.Adapter.handlers[b][c].length; g < i; ++g) f.Adapter.handlers[b][c][g].apply(this, [a]) | |
| }, | |
| extractEventData: function(b, c) { | |
| return c && c[b] || h | |
| }, | |
| onDomLoad: function(b) { | |
| var c = d.setTimeout(function() { | |
| b() | |
| }, 2E3); | |
| d.onload = function() { | |
| clearTimeout(c); | |
| b() | |
| } | |
| } | |
| }; | |
| typeof f.init !== "undefined" && f.init() | |
| })(window); | |
| (function(d, h) { | |
| var f = d.console || h, | |
| b = d.document, | |
| c = d.navigator, | |
| a = d.sessionStorage || !1, | |
| g = d.setTimeout, | |
| i = d.clearTimeout, | |
| n = d.setInterval, | |
| l = d.clearInterval, | |
| m = d.JSON, | |
| o = d.alert, | |
| k = d.History = d.History || {}, | |
| p = d.history; | |
| m.stringify = m.stringify || m.encode; | |
| m.parse = m.parse || m.decode; | |
| if (typeof k.init !== "undefined") throw Error("History.js Core has already been loaded..."); | |
| k.init = function() { | |
| if (typeof k.Adapter === "undefined") return !1; | |
| typeof k.initCore !== "undefined" && k.initCore(); | |
| typeof k.initHtml4 !== "undefined" && k.initHtml4(); | |
| return !0 | |
| }; | |
| k.initCore = function() { | |
| if (typeof k.initCore.initialized !== "undefined") return !1; | |
| else k.initCore.initialized = !0; | |
| k.options = k.options || {}; | |
| k.options.hashChangeInterval = k.options.hashChangeInterval || 100; | |
| k.options.safariPollInterval = k.options.safariPollInterval || 500; | |
| k.options.doubleCheckInterval = k.options.doubleCheckInterval || 500; | |
| k.options.storeInterval = k.options.storeInterval || 1E3; | |
| k.options.busyDelay = k.options.busyDelay || 250; | |
| k.options.debug = k.options.debug || !1; | |
| k.options.initialTitle = k.options.initialTitle || b.title; | |
| k.intervalList = []; | |
| k.clearAllIntervals = function() { | |
| var a, b = k.intervalList; | |
| if (typeof b !== "undefined" && b !== null) { | |
| for (a = 0; a < b.length; a++) l(b[a]); | |
| k.intervalList = null | |
| } | |
| }; | |
| k.debug = function() { | |
| k.options.debug && k.log.apply(k, arguments) | |
| }; | |
| k.log = function() { | |
| var a = !(typeof f === "undefined" || typeof f.log === "undefined" || typeof f.log.apply === "undefined"), | |
| c = b.getElementById("log"), | |
| g, i, l, d; | |
| a ? (i = Array.prototype.slice.call(arguments), g = i.shift(), typeof f.debug !== "undefined" ? f.debug.apply(f, [g, i]) : f.log.apply(f, [g, i])) : g = "\n" + arguments[0] + "\n"; | |
| for (i = 1, l = arguments.length; i < l; ++i) { | |
| d = arguments[i]; | |
| if (typeof d === "object" && typeof m !== "undefined") try { | |
| d = m.stringify(d) | |
| } catch (n) {} | |
| g += "\n" + d + "\n" | |
| } | |
| c ? (c.value += g + "\n-----\n", c.scrollTop = c.scrollHeight - c.clientHeight) : a || o(g); | |
| return !0 | |
| }; | |
| k.getInternetExplorerMajorVersion = function() { | |
| return k.getInternetExplorerMajorVersion.cached = typeof k.getInternetExplorerMajorVersion.cached !== "undefined" ? k.getInternetExplorerMajorVersion.cached : function() { | |
| for (var a = 3, c = b.createElement("div"), g = c.getElementsByTagName("i"); | |
| (c.innerHTML = "<\!--[if gt IE " + ++a + "]><i></i><![endif]--\>") && g[0];); | |
| return a > 4 ? a : !1 | |
| }() | |
| }; | |
| k.isInternetExplorer = function() { | |
| return k.isInternetExplorer.cached = typeof k.isInternetExplorer.cached !== "undefined" ? k.isInternetExplorer.cached : Boolean(k.getInternetExplorerMajorVersion()) | |
| }; | |
| k.emulated = { | |
| pushState: !Boolean(d.history && d.history.pushState && d.history.replaceState && !(/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(c.userAgent) || /AppleWebKit\/5([0-2]|3[0-2])/i.test(c.userAgent))), | |
| hashChange: Boolean(!("onhashchange" in d || "onhashchange" in b) || k.isInternetExplorer() && k.getInternetExplorerMajorVersion() < 8) | |
| }; | |
| k.enabled = !k.emulated.pushState; | |
| k.bugs = { | |
| setHash: Boolean(!k.emulated.pushState && c.vendor === "Apple Computer, Inc." && /AppleWebKit\/5([0-2]|3[0-3])/.test(c.userAgent)), | |
| safariPoll: Boolean(!k.emulated.pushState && c.vendor === "Apple Computer, Inc." && /AppleWebKit\/5([0-2]|3[0-3])/.test(c.userAgent)), | |
| ieDoubleCheck: Boolean(k.isInternetExplorer() && k.getInternetExplorerMajorVersion() < 8), | |
| hashEscape: Boolean(k.isInternetExplorer() && k.getInternetExplorerMajorVersion() < 7) | |
| }; | |
| k.isEmptyObject = function(a) { | |
| for (var b in a) return !1; | |
| return !0 | |
| }; | |
| k.cloneObject = function(a) { | |
| a ? (a = m.stringify(a), a = m.parse(a)) : a = {}; | |
| return a | |
| }; | |
| k.getRootUrl = function() { | |
| var a = b.location.protocol + "//" + (b.location.hostname || b.location.host); | |
| b.location.port && (a += ":" + b.location.port); | |
| a += "/"; | |
| return a | |
| }; | |
| k.getBaseHref = function() { | |
| var a = b.getElementsByTagName("base"), | |
| c = null, | |
| c = ""; | |
| a.length === 1 && (c = a[0], c = c.href.replace(/[^\/]+$/, "")); | |
| (c = c.replace(/\/+$/, "")) && (c += "/"); | |
| return c | |
| }; | |
| k.getBaseUrl = function() { | |
| return k.getBaseHref() || k.getBasePageUrl() || k.getRootUrl() | |
| }; | |
| k.getPageUrl = function() { | |
| return ((k.getState(!1, !1) || {}).url || b.location.href).replace(/\/+$/, "").replace(/[^\/]+$/, function(a) { | |
| return /\./.test(a) ? a : a + "/" | |
| }) | |
| }; | |
| k.getBasePageUrl = function() { | |
| return b.location.href.replace(/[#\?].*/, "").replace(/[^\/]+$/, function(a) { | |
| return /[^\/]$/.test(a) ? "" : a | |
| }).replace(/\/+$/, "") + "/" | |
| }; | |
| k.getFullUrl = function(a, b) { | |
| var c = a, | |
| g = a.substring(0, 1), | |
| b = typeof b === "undefined" ? !0 : b; | |
| /[a-z]+\:\/\//.test(a) || (c = g === "/" ? k.getRootUrl() + a.replace(/^\/+/, "") : g === "#" ? k.getPageUrl().replace(/#.*/, "") + a : g === "?" ? k.getPageUrl().replace(/[\?#].*/, "") + a : b ? k.getBaseUrl() + a.replace(/^(\.\/)+/, "") : k.getBasePageUrl() + a.replace(/^(\.\/)+/, "")); | |
| return c.replace(/\#$/, "") | |
| }; | |
| k.getShortUrl = function(a) { | |
| var b = k.getBaseUrl(), | |
| c = k.getRootUrl(); | |
| k.emulated.pushState && (a = a.replace(b, "")); | |
| a = a.replace(c, "/"); | |
| k.isTraditionalAnchor(a) && (a = "./" + a); | |
| return a = a.replace(/^(\.\/)+/g, "./").replace(/\#$/, "") | |
| }; | |
| k.store = {}; | |
| k.idToState = k.idToState || {}; | |
| k.stateToId = k.stateToId || {}; | |
| k.urlToId = k.urlToId || {}; | |
| k.storedStates = k.storedStates || []; | |
| k.savedStates = k.savedStates || []; | |
| k.normalizeStore = function() { | |
| k.store.idToState = k.store.idToState || {}; | |
| k.store.urlToId = k.store.urlToId || {}; | |
| k.store.stateToId = k.store.stateToId || {} | |
| }; | |
| k.getState = function(a, b) { | |
| typeof a === "undefined" && (a = !0); | |
| typeof b === "undefined" && (b = !0); | |
| var c = k.getLastSavedState(); | |
| !c && b && (c = k.createStateObject()); | |
| if (a) c = k.cloneObject(c), c.url = c.cleanUrl || c.url; | |
| return c | |
| }; | |
| k.getIdByState = function(a) { | |
| var b = k.extractId(a.url), | |
| c; | |
| if (!b) if (c = k.getStateString(a), typeof k.stateToId[c] !== "undefined") b = k.stateToId[c]; | |
| else if (typeof k.store.stateToId[c] !== "undefined") b = k.store.stateToId[c]; | |
| else { | |
| for (;;) if (b = (new Date).getTime() + String(Math.random()).replace(/\D/g, ""), typeof k.idToState[b] === "undefined" && typeof k.store.idToState[b] === "undefined") break; | |
| k.stateToId[c] = b; | |
| k.idToState[b] = a | |
| } | |
| return b | |
| }; | |
| k.normalizeState = function(a) { | |
| var c; | |
| if (!a || typeof a !== "object") a = {}; | |
| if (typeof a.normalized !== "undefined") return a; | |
| if (!a.data || typeof a.data !== "object") a.data = {}; | |
| c = { | |
| normalized: !0 | |
| }; | |
| c.title = a.title || ""; | |
| c.url = k.getFullUrl(k.unescapeString(a.url || b.location.href)); | |
| c.hash = k.getShortUrl(c.url); | |
| c.data = k.cloneObject(a.data); | |
| c.id = k.getIdByState(c); | |
| c.cleanUrl = c.url.replace(/\??\&_suid.*/, ""); | |
| c.url = c.cleanUrl; | |
| a = !k.isEmptyObject(c.data); | |
| if (c.title || a) c.hash = k.getShortUrl(c.url).replace(/\??\&_suid.*/, ""), /\?/.test(c.hash) || (c.hash += "?"), c.hash += "&_suid=" + c.id; | |
| c.hashedUrl = k.getFullUrl(c.hash); | |
| if ((k.emulated.pushState || k.bugs.safariPoll) && k.hasUrlDuplicate(c)) c.url = c.hashedUrl; | |
| return c | |
| }; | |
| k.createStateObject = function(a, b, c) { | |
| a = { | |
| data: a, | |
| title: b, | |
| url: c | |
| }; | |
| return a = k.normalizeState(a) | |
| }; | |
| k.getStateById = function(a) { | |
| a = String(a); | |
| return k.idToState[a] || k.store.idToState[a] || h | |
| }; | |
| k.getStateString = function(a) { | |
| a = { | |
| data: k.normalizeState(a).data, | |
| title: a.title, | |
| url: a.url | |
| }; | |
| return m.stringify(a) | |
| }; | |
| k.getStateId = function(a) { | |
| return k.normalizeState(a).id | |
| }; | |
| k.getHashByState = function(a) { | |
| return k.normalizeState(a).hash | |
| }; | |
| k.extractId = function(a) { | |
| return ((a = /(.*)\&_suid=([0-9]+)$/.exec(a)) ? String(a[2] || "") : "") || !1 | |
| }; | |
| k.isTraditionalAnchor = function(a) { | |
| return !/[\/\?\.]/.test(a) | |
| }; | |
| k.extractState = function(a, b) { | |
| var c = null, | |
| g, i, b = b || !1; | |
| (g = k.extractId(a)) && (c = k.getStateById(g)); | |
| c || (i = k.getFullUrl(a), (g = k.getIdByUrl(i) || !1) && (c = k.getStateById(g)), !c && b && !k.isTraditionalAnchor(a) && (c = k.createStateObject(null, null, i))); | |
| return c | |
| }; | |
| k.getIdByUrl = function(a) { | |
| return k.urlToId[a] || k.store.urlToId[a] || h | |
| }; | |
| k.getLastSavedState = function() { | |
| return k.savedStates[k.savedStates.length - 1] || h | |
| }; | |
| k.getLastStoredState = function() { | |
| return k.storedStates[k.storedStates.length - 1] || h | |
| }; | |
| k.hasUrlDuplicate = function(a) { | |
| var b = !1; | |
| return b = (b = k.extractState(a.url)) && b.id !== a.id | |
| }; | |
| k.storeState = function(a) { | |
| k.urlToId[a.url] = a.id; | |
| k.storedStates.push(k.cloneObject(a)); | |
| return a | |
| }; | |
| k.isLastSavedState = function(a) { | |
| var b = !1; | |
| if (k.savedStates.length) a = a.id, b = k.getLastSavedState(), b = b.id, b = a === b; | |
| return b | |
| }; | |
| k.saveState = function(a) { | |
| if (k.isLastSavedState(a)) return !1; | |
| k.savedStates.push(k.cloneObject(a)); | |
| return !0 | |
| }; | |
| k.getStateByIndex = | |
| function(a) { | |
| var b = null; | |
| return b = typeof a === "undefined" ? k.savedStates[k.savedStates.length - 1] : a < 0 ? k.savedStates[k.savedStates.length + a] : k.savedStates[a] | |
| }; | |
| k.getHash = function() { | |
| return k.unescapeHash(b.location.hash) | |
| }; | |
| k.unescapeString = function(a) { | |
| return a | |
| }; | |
| k.unescapeHash = function(a) { | |
| a = k.normalizeHash(a); | |
| return a = k.unescapeString(a) | |
| }; | |
| k.normalizeHash = function(a) { | |
| return a.replace(/[^#]*#/, "").replace(/#.*/, "") | |
| }; | |
| k.setHash = function(a, c) { | |
| var g, i; | |
| if (c !== !1 && k.busy()) return k.pushQueue({ | |
| scope: k, | |
| callback: k.setHash, | |
| args: arguments, | |
| queue: c | |
| }), !1; | |
| g = k.escapeHash(a); | |
| k.busy(!0); | |
| if ((i = k.extractState(a, !0)) && !k.emulated.pushState) k.pushState(i.data, i.title, i.url, !1); | |
| else if (b.location.hash !== g) k.bugs.setHash ? (i = k.getPageUrl(), k.pushState(null, null, i + "#" + g, !1)) : b.location.hash = g; | |
| return k | |
| }; | |
| k.escapeHash = function(a) { | |
| a = k.normalizeHash(a); | |
| a = d.escape(a); | |
| k.bugs.hashEscape || (a = a.replace(/\%21/g, "!").replace(/\%26/g, "&").replace(/\%3D/g, "=").replace(/\%3F/g, "?")); | |
| return a | |
| }; | |
| k.getHashByUrl = function(a) { | |
| a = String(a).replace(/([^#]*)#?([^#]*)#?(.*)/, "$2"); | |
| return a = k.unescapeHash(a) | |
| }; | |
| k.setTitle = function(a) { | |
| var c = a.title, | |
| g; | |
| c || (g = k.getStateByIndex(0)) && g.url === a.url && (c = g.title || k.options.initialTitle); | |
| try { | |
| b.getElementsByTagName("title")[0].innerHTML = c.replace("<", "<").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