Advertisement
MrSiir

Profile Spotify Code

Dec 6th, 2011
984
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. "use strict";
  2.  
  3. sp = getSpotifyApi(1);
  4.  
  5. var dom     = sp.require("sp://import/scripts/dom");
  6. var dnd     = sp.require("sp://import/scripts/dnd");
  7. var ui      = sp.require("sp://import/scripts/ui");
  8. var util    = sp.require('sp://import/scripts/util');
  9. var r       = sp.require("sp://import/scripts/react");
  10. var fx      = sp.require("sp://import/scripts/fx");
  11. var fs      = sp.require("sp://import/scripts/fs");
  12. var hermes  = sp.require("sp://import/scripts/hermes");
  13. var popover = sp.require("sp://import/scripts/popover");
  14. var lang    = sp.require("sp://import/scripts/language");
  15. var catalog = lang.loadCatalog("cef_views");
  16. var _       = partial(lang.getString, catalog, "Profile");
  17. var _g      = partial(lang.getString, catalog, "Generic");
  18. var token   = sp.require("scripts/token");
  19. var toplist = sp.require("scripts/toplist");
  20. var tokenInput = new token.TokenInput("uris");
  21.  
  22. // How often we need to re-subscribe to the presence service
  23. var PRESENCE_SUBSCRIPTION_EXPIRATION = 170000;
  24.  
  25. var PRESENCE_TYPES = {
  26.     UNKNOWN: -1,
  27.     FACEBOOK_ACTIVITY: 0,
  28.     TRACK_FINISHED_PLAYING: 1,
  29.     PLAYLIST_PUBLISHED: 2,
  30.     PLAYLIST_TRACK_ADDED: 3,
  31.     PLAYLIST_TRACK_STARRED: 4
  32. };
  33.  
  34. var MSGBAR_TYPES = {
  35.     INFORMATION: 0,
  36.     WARNING: 1,
  37.     ERROR: 2,
  38.     INFORMATION_HEART: 3
  39. };
  40.  
  41. var windowLoad  = r.fromDOMEvent(window, "load");
  42. var argsChanged = r.fromDOMEvent(sp.core, "argumentsChanged");
  43. var login  = r.fromDOMEvent(sp.core, "login");
  44. var logout = r.fromDOMEvent(sp.core, "logout").subscribe(userIsOffline);
  45.  
  46. var t = 0;
  47.  
  48. var isFacebookProfile = false;
  49.  
  50. var relations = sp.social.relations;
  51. var favorites = sp.social.getFavorites();
  52.  
  53. // SUB to Hermes PresenceStates when any of these events happen, and update profile page
  54. r.merge(login, r.merge(windowLoad, argsChanged)).subscribe(loadUser);
  55.  
  56. function subHermes(data) {
  57.     sp.core.getHermes("SUB", "hm://presence/user/",
  58.         [data.canonicalUsername], {
  59.         onSuccess: function() {},
  60.         onFailure: partial(sp.core.showClientMessage, MSGBAR_TYPES.ERROR, _g("sGenericPresenceError")),
  61.         onComplete: function() {}
  62.     });
  63.     t = setTimeout(function() {
  64.         subHermes(data);
  65.     }, PRESENCE_SUBSCRIPTION_EXPIRATION);
  66. }
  67.  
  68. function getHermes(data){
  69.     sp.core.getHermes("GET", "hm://presence/user/",
  70.         [data.canonicalUsername], {
  71.         onSuccess: function() {
  72.             var state;
  73.             try {
  74.                 state = sp.core.parseHermesReply("PresenceState", arguments[0]);
  75.                 hermes.stringFromPresenceState(state, function(s) {
  76.                     dom.queryOne(".activity").innerHTML = s;
  77.                 });
  78.             }
  79.             catch (err) {
  80.                 return false;
  81.             }
  82.         },
  83.         onFailure: partial(sp.core.showClientMessage, MSGBAR_TYPES.ERROR, _g("sGenericPresenceError")),
  84.         onComplete: function() {}
  85.     });
  86. }
  87.  
  88. function _updateFavoriteButton(button) {
  89.     var user = button.user;
  90.     var isFavorite = (favorites.all().indexOf(user.uri) != -1);
  91.     button.innerHTML = isFavorite ? _("sProfileRemoveFavorite") : _("sProfileAddFavorite");
  92. }
  93.  
  94. function _toggleFavoriteState(user) {
  95.     var uri = user.uri;
  96.     if (favorites.all().indexOf(uri) != -1)
  97.         favorites.remove(uri);
  98.     else
  99.         favorites.add(uri);
  100. }
  101.  
  102. function _isFriend(person) {
  103.     var match = filter(function(knownFriend) {
  104.         return person.uri === knownFriend;
  105.     }, relations.all());
  106.  
  107.     return 0 === match.length ? false : true;
  108. }
  109.  
  110. function fillActivityWithState(state) {
  111.     hermes.stringFromPresenceState(state, function(str) {
  112.         dom.queryOne(".activity").innerHTML = str;
  113.     });
  114. }
  115.  
  116. function userIsOffline() {
  117.     var body = document.querySelector("body");
  118.     var template = document.createDocumentFragment();
  119.     var offlineOverlay = new dom.Element('div', {className:'overlay'});
  120.  
  121.     body.className = "offline";
  122.     template.textContent = fs.readFile("templates/offline.html");
  123.     body.innerHTML = lang.format(template.textContent, _("sProfileUserOffline"));
  124. }
  125.  
  126. function getNamedArgument(name) {
  127.     var args = sp.core.getArguments();
  128.     if (args.length < 2) return null;
  129.     if (args[0] != name) return null;
  130.     return args[1];
  131. }
  132.  
  133. var resize = r.fromDOMEvent(window, "resize");
  134. function restyleList(e) {
  135.     var targetWrapper   = dom.queryOne('.list-wrapper ul'),
  136.         listItems       = dom.query('li', targetWrapper),
  137.         list            = [],
  138.         minMarginLeft   = 10,
  139.         minWidth        = 128,
  140.         visibleWidth    = targetWrapper.clientWidth,
  141.         columns         = Math.floor( (visibleWidth + minMarginLeft) / (minWidth + minMarginLeft) ),
  142.         marginLeft      = Math.floor( (visibleWidth - (columns * minWidth)) / (columns - 1) );
  143.  
  144.     var items = listItems.slice(0, columns);
  145.     listItems.forEach(function(elem, index, arr) {
  146.         elem.style.opacity = 0;
  147.     });
  148.  
  149.     items.forEach(function(elem, index, arr) {
  150.         if (e && 'resize' == e.type) {
  151.             elem.style.webkitTransitionProperty = 'margin-left, opacity';
  152.         }
  153.         elem.style.opacity = 1;
  154.         if (index > 0) {
  155.             if (marginLeft >= minMarginLeft) {
  156.                 elem.style.marginLeft = marginLeft + 'px';
  157.             }
  158.         }
  159.     });
  160. }
  161.  
  162. function isVisible(obj) {
  163.     if (obj == document) return true
  164.  
  165.     if (!obj) return false
  166.     if (!obj.parentNode) return false
  167.     if (obj.style) {
  168.         if (obj.style.display == 'none') return false
  169.         if (obj.style.visibility == 'hidden') return false
  170.     }
  171.  
  172.     //Try the computed style in a standard way
  173.     if (window.getComputedStyle) {
  174.         var style = window.getComputedStyle(obj, "")
  175.         if (style.display == 'none') return false
  176.         if (style.visibility == 'hidden') return false
  177.     }
  178.  
  179.     return isVisible(obj.parentNode)
  180. }
  181.  
  182. /**
  183.  * initialize profile page
  184.  * @param {user} the current user viewing
  185.  * @param {isSelf} is it sp.core.user
  186.  */
  187. function init(user, isSelf) {
  188.     var profilePic      = new ui.SPImage(user.picture);
  189.     var tl              = new toplist.TopList({
  190.         maxItems: 15,
  191.         user: user
  192.     });
  193.     var headerAnchor    = dom.queryOne("h1 a");
  194.     var form            = dom.queryOne("form");
  195.     var searchInput     = tokenInput.input;
  196.     var outputElement   = tokenInput.output;
  197.     var messageElement  = tokenInput.message;
  198.     var added           = false;
  199.     var createButton    = function() {
  200.         if (!isSelf && _isFriend(user) && !added) {
  201.             var isFavorite = (favorites.all().indexOf(user.uri) != -1);
  202.             var favoriteButton = document.createElement("button");
  203.             var buttonWrapper = document.createElement("span");
  204.             favoriteButton.user = user;
  205.  
  206.             favoriteButton.classList.add("button");
  207.             favoriteButton.innerHTML = isFavorite ? _("sProfileRemoveFavorite") : _("sProfileAddFavorite");
  208.  
  209.             buttonWrapper.appendChild(favoriteButton);
  210.  
  211.             dom.queryOne( isFacebookProfile? ".picture": ".profile h1" ).appendChild(buttonWrapper);
  212.  
  213.             r.fromDOMEvent(favoriteButton, "click").subscribe(function(e) {
  214.                 _toggleFavoriteState(user);
  215.             });
  216.             r.fromDOMEvent(favorites, "change").subscribe(function(e) {
  217.                 _updateFavoriteButton(favoriteButton);
  218.             });
  219.  
  220.             added = true;
  221.         }
  222.     };
  223.  
  224.     r.fromDOMEvent(headerAnchor, "click").subscribe(function(e){
  225.         e.preventDefault();
  226.     });
  227.  
  228.     r.fromDOMEvent(relations, "change").subscribe(createButton);
  229.  
  230.     dom.adopt(dom.queryOne(".picture"), profilePic.node);
  231.     dom.adopt(dom.queryOne("form li"), tokenInput.node);
  232.     dom.adopt(dom.queryOne("form li:nth-child(2)"), tokenInput.messageNode);
  233.  
  234.     createButton();
  235.  
  236.     tl.fetchList({
  237.         loadTemplateCb: function(obj) {
  238.             var body = dom.queryOne("body");
  239.             var template = fs.readFile("templates/list.html");
  240.             var fragment = document.createDocumentFragment();
  241.             var div = document.createElement("div");
  242.             var replacements = [
  243.                 "top-"+ ( isFacebookProfile ? "facebook" : "{0}" ),
  244.                 ( "artists" === obj.listtype ? _("sProfileTopArtists") : lang.format(_("sProfileSendTopTracks"), user.name) )
  245.             ];
  246.  
  247.             replacements[0] = lang.format(replacements[0], obj.listtype);
  248.             div.innerHTML = lang.format(template, replacements);
  249.             dom.adopt(dom.queryOne(".list-wrapper", div), tl.toplist);
  250.  
  251.             fragment.appendChild(div.childNodes[0]);
  252.             tl.toplist = fragment;
  253.  
  254.             body.classList.add(obj.listtype);
  255.             dom.queryOne("section .loader", tl.toplist)
  256.                 .parentNode
  257.                 .removeChild(dom.queryOne("section .loader", tl.toplist));
  258.  
  259.             if ("artists" !== obj.listtype || isFacebookProfile) {
  260.                 var aligner = new dom.Element("div", {
  261.                     className: "centered",
  262.                     id: "search-button-wrapper"
  263.                 });
  264.                 var searchButton = new dom.Element("button", {
  265.                     className: "sp-button flat",
  266.                     id: "search-button",
  267.                     type: "button"
  268.                 });
  269.                 var fadeOutAnimationOptions = {
  270.                     opacity: 0
  271.                 };
  272.                 var fadeInAnimationOptions = {
  273.                     opacity: 1
  274.                 };
  275.                 searchButton.appendChild(document.createTextNode(_("sProfileSearchLabel")));
  276.                 r.fromDOMEvent(searchButton, "click").subscribe(function(e){
  277.                     e.preventDefault();
  278.                     e.stopPropagation();
  279.                     var form = dom.queryOne("form");
  280.                     var formAnim = new fx.Animation(form);
  281.                     var listSection = dom.queryOne(".list-section");
  282.                     var listAnim = new fx.Animation(listSection);
  283.                     if (isVisible(form)) {
  284.                         formAnim.animate(fadeOutAnimationOptions).then(function() {
  285.                             form.style.display = "none";
  286.                             listSection.style.display = "block";
  287.                             dom.queryOne("#search-button").innerHTML = _("sProfileSearchLabel");
  288.                             listAnim.animate(fadeInAnimationOptions).then(function() {
  289.                                 if (!isFacebookProfile) {
  290.                                     restyleList();
  291.                                 }
  292.                             });
  293.                         });
  294.                     } else {
  295.                         popover.hidePopover();
  296.                         listAnim.animate(fadeOutAnimationOptions).then(function() {
  297.                             listSection.style.display = "none";
  298.                             form.style.display = "block";
  299.                             dom.queryOne("#search-button").innerHTML = _("sProfilePickSomethingLabel");
  300.                             formAnim.animate(fadeInAnimationOptions);
  301.                         });
  302.                     }
  303.                 });
  304.                 dom.adopt(aligner, searchButton);
  305.                 dom.adopt(tl.toplist, aligner);
  306.  
  307.                 dom.query("button.share", tl.toplist).forEach(function(elem, index, source) {
  308.                     r.fromDOMEvent(elem, "click").subscribe(function(e) {
  309.                         e.preventDefault();
  310.                         e.stopPropagation();
  311.                         popover.sharePopup(tl.opts.user, elem.parentNode.parentNode.href, elem.parentNode, {
  312.                             relativeNode: dom.queryOne(".list-section"),
  313.                             offsetLeft: 30,
  314.                             offsetFlippedLeft: 60
  315.                         });
  316.                     });
  317.                 });
  318.             }
  319.         },
  320.         adoptToplistCb: function() {
  321.             if ("tracks" === tl.listtype && !isFacebookProfile) {
  322.                 dom.adopt(dom.queryOne(".profile"), tl.toplist);
  323.             } else {
  324.                 dom.adopt(dom.queryOne("body"), tl.toplist);
  325.             }
  326.             if (!isFacebookProfile) {
  327.                 resize.subscribe(util.debounce(restyleList, 500));
  328.                 restyleList();
  329.             }
  330.         }
  331.     });
  332.  
  333.     r.fromDOMEvent(form, "submit").subscribe(function(e) {
  334.         var tokens = tokenInput.getValues();
  335.         var message = e.target.message.value;
  336.         var failure = 0;
  337.         var showSendingTracksOverlay = function() {
  338.             var container = dom.queryOne(".send-tunes-container");
  339.             var fragment = document.createDocumentFragment();
  340.             var div = new dom.Element("div", {
  341.                 className: 'send-music'
  342.             });
  343.             var innerDiv = document.createElement("div");
  344.             innerDiv.innerHTML = lang.format('<img src="sp://import/img/sent-icon.png" /><span>{0}</span>', _("sProfileMusicSent"));
  345.             dom.adopt(div, innerDiv);
  346.             dom.adopt(fragment, div);
  347.             dom.adopt(container, fragment);
  348.             r.fromDOMEvent(div, "webkitAnimationEnd").subscribe(function(e){
  349.                 var parent = e.target.parentNode;
  350.                 parent.removeChild(e.target);
  351.             });
  352.         };
  353.         var onFailureCb = partial(sp.core.showClientMessage, MSGBAR_TYPES.ERROR, _g("sGenericSendMessageError"));
  354.         var onCompleteCb = function() {
  355.             if (null !== user.facebookUid && 2 === failure || null === user.facebookUid && 1 === failure) {
  356.                 onFailureCb();
  357.             }
  358.         };
  359.  
  360.         showSendingTracksOverlay();
  361.  
  362.         e.preventDefault();
  363.  
  364.         // Send to Spotify Inbox, now with callbacks
  365.         if (user.canonicalUsername) {
  366.             sp.social.sendToInbox(user.canonicalUsername,
  367.                 message,
  368.                 tokens,
  369.                 {
  370.                     onSuccess: function() {},
  371.                     onFailure: function() {
  372.                         failure++;
  373.                     },
  374.                     onComplete: onCompleteCb
  375.                 }
  376.             );
  377.         }
  378.  
  379.         // Send to Facebook, if available
  380.         if (null !== user.facebookUid) {
  381.             var postObj = {
  382.                 fb_uid: [user.facebookUid],
  383.                 message: message,
  384.                 spotify_uri: map(sp.core.spotifyUriToHttpLink, tokens)
  385.             };
  386.  
  387.             sp.core.getHermes("POST", "hm://social/post_to_facebook",
  388.                 [
  389.                     ["FacebookMessagePost", postObj]
  390.                 ],
  391.                 {
  392.                     onSuccess: function() {},
  393.                     onFailure: function() {
  394.                         failure++;
  395.                     },
  396.                     onComplete: onCompleteCb
  397.                 }
  398.             );
  399.         }
  400.  
  401.         e.target.reset();
  402.         tokenInput.clear();
  403.         e.target.classList.add("success");
  404.         e.target.offsetWidth;
  405.         e.target.classList.remove("success");
  406.     });
  407.  
  408.     // Hermes event received, update activity
  409.     r.fromDOMEvent(sp.core, "hermes").subscribe(function(e) {
  410.         var uri = e.data[0],
  411.             username,
  412.             state;
  413.  
  414.         if (user.username) {
  415.             if (uri.indexOf("hm://presence/user/") !== -1) {
  416.                 username = uri.slice("hm://presence/user/".length, -1); // Removes last slash
  417.                 if (username == user.username) {
  418.                     state = sp.core.parseHermesReply("PresenceState", e.data[1]);
  419.                     fillActivityWithState(state);
  420.                 }
  421.             }
  422.         }
  423.     });
  424. }
  425.  
  426. function initialize(data, isSelf) {
  427.     var template        = document.createDocumentFragment();
  428.     var body            = dom.queryOne("body");
  429.  
  430.     if (data) {
  431.         body.className = '';
  432.         if (!isFacebookProfile) {
  433.             getHermes(data);
  434.             subHermes(data);
  435.         } else {
  436.             body.className = 'facebook';
  437.         }
  438.  
  439.         template.textContent = fs.readFile("templates/header.html");
  440.  
  441.         body.innerHTML = lang.format(template.textContent, data.uri, data.name, " ",
  442.             lang.format(_("sProfileSendTopTracks"), data.name),
  443.             _("sProfileMessage"), _("sProfileSend"));
  444.  
  445.         init(data, isSelf);
  446.     } else {
  447.         template.textContent = fs.readFile("templates/error.html");
  448.         body.innerHTML = lang.format(template.textContent, _("sProfileUnknownUser"), " ");
  449.     }
  450. }
  451.  
  452. function loadUser() {
  453.     // spotify:app:profile:user:parbo
  454.     // spotify:app:profile:user:pannpann
  455.     // spotify:app:profile:facebook:1362172452
  456.     var username = getNamedArgument("user");
  457.     var facebook = getNamedArgument("facebook");
  458.     var callbacks = {
  459.         onSuccess: function(user) {
  460.             initialize(user, false);
  461.         },
  462.         onFailure: function(errorCode) {
  463.             sp.core.showClientMessage(MSGBAR_TYPES.ERROR, _("sProfileLoadUserError"));
  464.  
  465.             var template        = document.createDocumentFragment();
  466.             var body            = dom.queryOne("body");
  467.             template.textContent = fs.readFile("templates/error.html");
  468.             body.innerHTML = lang.format(template.textContent, _("sProfileUnknownUser"), " ");
  469.         },
  470.         onComplete: id
  471.     };
  472.  
  473.     if (sp.core.getLoginMode() == 1) {
  474.         if (username) {
  475.             isFacebookProfile = false;
  476.             sp.social.getUserByUsername(username, callbacks);
  477.         } else if (facebook) {
  478.             isFacebookProfile = true;
  479.             sp.social.getUserByFacebookUid(facebook, callbacks);
  480.         } else {
  481.             isFacebookProfile = false;
  482.             initialize(sp.core.user, true);
  483.         }
  484.     } else {
  485.         userIsOffline();
  486.     }
  487. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement