tuner2.js
Go to the documentation of this file.
1 if (typeof(Cc) == "undefined")
2  var Cc = Components.classes;
3 if (typeof(Ci) == "undefined")
4  var Ci = Components.interfaces;
5 if (typeof(Cu) == "undefined")
6  var Cu = Components.utils;
7 
8 if (typeof(RADIO_ICON_SMALL) == "undefined")
9  var RADIO_ICON_SMALL = "chrome://sb-lastfm/skin/icon_radio_small.png";
10 if (typeof(GLOBE_ICON) == "undefined")
11  var GLOBE_ICON = "chrome://sb-lastfm/skin/homepage.png";
12 if (typeof(LASTFM_ICON) == "undefined")
13  var LASTFM_ICON = "chrome://sb-lastfm/skin/as.png";
14 if (typeof(htmlns) == "undefined")
15  var htmlns = "http://www.w3.org/1999/xhtml";
16 
17 if (typeof(DISPLAY_SEARCH_LIMIT) == "undefined")
18  var DISPLAY_SEARCH_LIMIT = 16;
19 if (typeof(DISPLAY_RECENT_STATIONS_LIMIT) == "undefined")
20  var DISPLAY_RECENT_STATIONS_LIMIT = 10;
21 if (typeof(DISPLAY_RELATED_TAGS_LIMIT) == "undefined")
22  var DISPLAY_RELATED_TAGS_LIMIT = 6;
23 if (typeof(DISPLAY_RELATED_ARTISTS_LIMIT) == "undefined")
24  var DISPLAY_RELATED_ARTISTS_LIMIT = 6;
25 if (typeof(DISPLAY_TOP_FANS_LIMIT) == "undefined")
26  var DISPLAY_TOP_FANS_LIMIT = 6;
27 if (typeof(LIMIT_NAV_RESULTS) == "undefined")
28  var LIMIT_NAV_RESULTS = 10;
29 
30 if (typeof(LibraryUtils) == "undefined")
31  Cu.import("resource://app/jsmodules/sbLibraryUtils.jsm");
32 if (typeof(SBProperties) == "undefined")
33  Cu.import("resource://app/jsmodules/sbProperties.jsm");
34 
35 if (typeof(gBrowser) == "undefined")
36  var gBrowser = Components.classes['@mozilla.org/appshell/window-mediator;1']
37  .getService(Components.interfaces.nsIWindowMediator)
38  .getMostRecentWindow('Songbird:Main').gBrowser;
39 
40 var LastfmTuner = {
41  // Default to artist search
42  searchType: "artist",
43 
44  init: function() {
45  this._metrics = Cc['@songbirdnest.com/Songbird/Metrics;1']
46  .getService(Ci.sbIMetrics);
47 
48  // Create our string bundle
49  LastfmTuner._strings = Cc["@mozilla.org/intl/stringbundle;1"]
50  .getService(Ci.nsIStringBundleService)
51  .createBundle("chrome://sb-lastfm/locale/overlay.properties");
52 
53  // Add a pointer to our service
54  LastfmTuner.svc = Cc['@songbirdnest.com/lastfm;1']
55  .getService().wrappedJSObject;
56 
57  // And a pointer to nsIJSON
58  LastfmTuner.jsonSvc = Cc["@mozilla.org/dom/json;1"]
59  .createInstance(Ci.nsIJSON);
60 
61  // Add our listeners for login/logout state change
62  LastfmTuner.svc.listeners.add(LastfmTuner);
63 
64  LastfmTuner.populateBox("nav-recent-stations",
65  LastfmTuner.dataRecentStations);
66 
67  // Add a preferences observer
68  LastfmTuner.prefs = Cc["@mozilla.org/preferences-service;1"]
69  .getService(Ci.nsIPrefService).getBranch("extensions.lastfm.")
70  .QueryInterface(Ci.nsIPrefBranch2);
71  LastfmTuner.prefs.addObserver("", LastfmTuner, false);
72 
73  // populate the Songbird boxes
74  LastfmTuner.populateBox("nav-played-artists-sb",
75  LastfmTuner.dataSBMostPlayedArtists);
76  LastfmTuner.populateBox("nav-rated-artists-sb",
77  LastfmTuner.dataSBHighestRatedArtists);
78  LastfmTuner.populateBox("nav-genres-sb",
79  LastfmTuner.dataSBGenres);
80 
81  // Set up the header display
82  LastfmTuner.setHeaderDisplay();
83  $("#lastfm-header-style").click(function(e) {
84  e.preventDefault();
85  e.stopPropagation();
86  LastfmTuner.toggleHeaderDisplay();
87  });
88 
89  },
90 
91  fini: function() {
92  LastfmTuner.svc.listeners.remove(LastfmTuner);
93  LastfmTuner.prefs.removeObserver("", LastfmTuner, false);
94  },
95 
96  loadPage: function(url, metricKey) {
97  LastfmTuner._metrics.metricsInc('lastfm', 'pageclick', metricKey);
98  gBrowser.loadOneTab(url);
99  },
100 
101  // sbILastFm listeners for events generated by the service
102  onAuthorisationSuccess: function() {
103  },
104  onLoginSucceeded: function() {
105  dump("login success hook called: " + LastfmTuner.svc.subscriber + "\n");
106  LastfmTuner.populateBox("nav-recommended-artists", this.dataRecArtists);
107  LastfmTuner.populateBox("nav-top-artists", this.dataTopArtists);
108  LastfmTuner.populateBox("nav-top-tags", this.dataTopTags);
109  LastfmTuner.populateBox("nav-friends", this.dataMyFriends, 999);
110  LastfmTuner.populateBox("nav-neighbours", this.dataMyNeighbours);
111 
112  // expose the last.fm stations
113  $("#right-nav-last-fm").slideDown("slow");
114 
115  if (LastfmTuner.svc.subscriber) {
116  $("#subscriber-page").hide();
117  }
118  },
119  onLoginFailed: function() {
120  },
121  onProfileUpdated: function() {
122  // Set the profile image
123  var avatar = "chrome://sb-lastfm/skin/default-avatar.png";
124  if (LastfmTuner.svc.avatar)
125  avatar = LastfmTuner.svc.avatar;
126  var imageEl = document.getElementById("lastfm-user-image");
127  imageEl.src = avatar;
128  imageEl.onload = function() {
129  $("#user-profile").fadeIn("slow");
130  }
131 
132  var name = LastfmTuner.svc.realname;
133  LastfmTuner.profileurl = LastfmTuner.svc.profileurl;
134 
135  // Set the username
136  $("#lastfm-user-name").empty();
137  $("#lastfm-user-name").append(name);
138 
139  // Fixup the links for the personal stations
140  var username = LastfmTuner.svc.username;
141  $("#nav-user-stations-results a").each(function() {
142  this.href = "lastfm://user/" + username + "/" + this.id;
143  });
144 
145  // Show the personal stations
146  //$("#lastfm-user-stations").fadeIn("slow");
147 
148  // if logged in, hide the login lightbox
149  $("#login-page").hide();
150  if (!LastfmTuner.svc.subscriber)
151  $("#subscriber-page").show();
152  },
153  onLoveBan: function() {
154  },
155  onShouldScrobbleChanged: function() {
156  },
157  onUserLoggedOutChanged: function() {
158  // make the user info stuff go away
159  $("#user-profile").fadeOut("slow");
160  $("#lastfm-user-stations").fadeOut("slow");
161 
162  // hide the last.fm stations
163  $("#right-nav-last-fm").slideUp("slow");
164 
165  // if not logged in, show the login lightbox
166  $("#login-page").show();
167  $("#subscriber-page").hide();
168  },
169  showLogin: function() {
170  Cc['@mozilla.org/appshell/window-mediator;1']
171  .getService(Ci.nsIWindowMediator)
172  .getMostRecentWindow('Songbird:Main').LastFm.showPanel();
173  },
174  onLoggedInStateChanged: function() {
175  },
176  onErrorChanged: function() {
177  },
178  onLoginBegins: function() {
179  },
180  onLoginCancelled: function() {
181  },
182 
183  /*
184  * Search routines
185  */
186 
187  collectResults: function(success, xml, type, limit) {
188  if (!success) {
189  dump("Failed search\n");
190  return null;
191  }
192  var tagResults = xml.getElementsByTagName(type);
193  if (tagResults.length == 0) {
194  dump("No results found\n");
195  return null;
196  }
197 
198  function xmlText (node, tag, attr, value) {
199  var tags = node.getElementsByTagName(tag);
200  if (tags.length) {
201  if (!attr)
202  return tags[0].textContent;
203  else {
204  for (var i=0; i<tags.length; i++) {
205  if (tags[i].getAttribute(attr) == value) {
206  return tags[i].textContent;
207  }
208  }
209  return tags[0].textContent;
210  }
211  } else {
212  return "";
213  }
214  }
215 
216  var results = new Array();
217  for (var i=0; i<tagResults.length; i++) {
218  var tagResult = tagResults[i];
219  var notStreamable = (xmlText(tagResult, 'streamable') == "0");
220  if (notStreamable) {
221  continue;
222  }
223 
224  var info = {
225  name: xmlText(tagResult, 'name')
226  .replace(/&/g, "&amp;").replace(/>/g, "gt;")
227  .replace(/</g, "&lt;").replace(/"/g, "&quot;"),
228  url: xmlText(tagResult, 'url'),
229  type: type
230  }
231  var pattern, replace;
232  switch (type) {
233  case "artist":
234  pattern = /^.*www\.last\.fm\/music/;
235  replace = "lastfm://artist";
236  info.sImageUrl = xmlText(tagResult,
237  'image', "size", "small");
238  info.mImageUrl = xmlText(tagResult,
239  'image', "size", "medium");
240  info.lImageUrl = xmlText(tagResult,
241  'image', "size", "large");
242  break;
243  case "tag":
244  pattern = /^.*www\.last\.fm\/tag/;
245  replace = "lastfm://tag";
246  info.sImageUrl = "chrome://sb-lastfm/skin/tag.png";
247  info.mImageUrl = "chrome://sb-lastfm/skin/tag_m.png";
248  info.lImageUrl = "chrome://sb-lastfm/skin/tag_l.png";
249  break;
250  case "user":
251  pattern = /^.*www\.last\.fm\/user/;
252  replace = "lastfm://user";
253  info.sImageUrl = xmlText(tagResult,
254  'image', "size", "small");
255  info.mImageUrl = xmlText(tagResult,
256  'image', "size", "medium");
257  info.lImageUrl = xmlText(tagResult,
258  'image', "size", "large");
259  break;
260  default: break;
261  }
262 
263  if (!info.sImageUrl)
264  info.sImageUrl = "http://cdn.last.fm/flatness/catalogue/noimage/2/default_user_small.png";
265  if (!info.mImageUrl)
266  info.mImageUrl = "http://cdn.last.fm/flatness/catalogue/noimage/2/default_user_medium.png";
267  if (!info.lImageUrl)
268  info.lImageUrl = "http://cdn.last.fm/flatness/catalogue/noimage/2/default_user_large.png";
269  info.stationUrl = info.url.replace(pattern, replace);
270  results.push(info);
271 
272  // if we have enough results, then stop
273  if (limit && results.length >= limit)
274  break;
275  }
276  return results;
277  },
278 
279  runSearch: function() {
280  var search = $('#search-box')[0].value;
281 
282  // Make the search button "busy", and clear the results area
283  var e = $('#explorer');
284  e.empty();
285 
286  e.append("<div id='artist-results' /><div id='tag-results' />");
287 
288  // Get the artist results
289  LastfmTuner.svc.apiCall("artist.search", {artist:search},
290  function response(success, xml)
291  {
292  var results = LastfmTuner.collectResults(success, xml, "artist",
293  DISPLAY_SEARCH_LIMIT);
294 
295  var ar = $("#artist-results", e);
296  if (!results) {
297  var str = LastfmTuner._strings.formatStringFromName(
298  "lastfm.radio.no_artists_found", [search], 1);
299  ar.append("<h2 class='title'>" + str + "</h2>");
300  $(window).resize();
301  return;
302  }
303 
304  var artistsHeader = LastfmTuner._strings.GetStringFromName(
305  "lastfm.radio.artists");
306  ar.append("<h2 class='title'>" + artistsHeader + "</h2>");
307  LastfmTuner.drawMultipleResults(results, "artist", "l", 9, ar,
308  function(station) {
309  LastfmTuner.drawSingleArtist(station.stationInfo);
310  });
311  $(window).resize();
312  });
313  LastfmTuner.svc.apiCall("tag.search", {tag:search},
314  function response(success, xml)
315  {
316  var results = LastfmTuner.collectResults(success, xml, "tag",
317  DISPLAY_SEARCH_LIMIT);
318 
319  var tr = $("#tag-results", e);
320  if (!results) {
321  var str = LastfmTuner._strings.formatStringFromName(
322  "lastfm.radio.no_tags_found", [search], 1);
323  tr.append("<h2 class='title'>" + str + "</h2>");
324  $(window).resize();
325  return;
326  }
327 
328  var tagsHeader = LastfmTuner._strings.GetStringFromName(
329  "lastfm.radio.tags");
330  tr.append("<h2 class='title'>" + tagsHeader + "</h2>");
331  LastfmTuner.drawMultipleResults(results, "tag", "s", 9, tr,
332  function(station) {
333  LastfmTuner.drawSingleTag(station.stationInfo);
334  });
335  $(window).resize();
336  });
337  },
338 
339  drawMultipleResults: function(results, type, imgSize, limit, node, onclick)
340  {
341  var resultClass = type + "-result";
342  var imageClass = type + "-image";
343  node.append("<div class='search-results'>");
344  results.forEach(function(val, i, arr) {
345  if (i >= limit)
346  return;
347  var singleResult;
348  var image = val[imgSize + "ImageUrl"];
349  if (type == "tag") {
350  var playStr = LastfmTuner._strings.GetStringFromName(
351  "lastfm.radio.play");
352  singleResult = $(
353  "<div class='single-result " + resultClass + "'>" +
354 
355  "<div class='station-info'>" +
356  "<div class='station-name'>" +
357  "<img class='" + imageClass + "' src='" + image +
358  "'/>" + val.name +
359  "</div>" +
360 
361  "<div class='station-nav'>" +
362  "<div class='station-play'><a href='" + val.stationUrl +
363  "'><img src='" + RADIO_ICON_SMALL +
364  "'/>" + playStr + "</a></div>" + //station-play
365  "<div class='station-web'>" +
366  "<img height='12' src='" + GLOBE_ICON + "'/>" +
367  "</div>" +
368  "</div>" + //station-nav
369  "</div>" + //station-info
370 
371  "</div>");
372 
373  var nav = $(".station-nav", singleResult);
374  nav.hide();
375  singleResult.hover(function over(e) {
376  var p = $(e.target).position();
377  var x = p.left + 60;
378  var y = p.top;
379  nav.css({'left': x, 'top': y});
380  nav.fadeIn('fast');
381  }, function out(e) {
382  nav.hide();
383  });
384  } else {
385  var playStr = LastfmTuner._strings.GetStringFromName(
386  "lastfm.radio.play");
387  singleResult = $(
388  "<div class='single-result " + resultClass + "'>" +
389 
390  // the artist image
391  "<div class='img-outer-shadow-bottom'><div class='img-outer-shadow'><div class='img-outer'><div class='img-inner'>" +
392  "<img src='" + image + "' height='80' border='0' />" +
393  "</div></div></div></div>" +
394 
395  "<div class='station-info'>" + val.name +
396  "<div class='station-nav'>" +
397  "<div class='station-play'><a href='" + val.stationUrl +
398  "'><img src='" + RADIO_ICON_SMALL +
399  "'/>" + playStr + "</a></div>" + //station-play
400  "<div class='station-web'>" +
401  "<img height='12' src='" + GLOBE_ICON + "'/>" +
402  "</div>" +
403  "</div>" + //station-nav
404  "</div>" + //station-info
405 
406  "</div>");
407 
408  $(".station-nav", singleResult).hide();
409  singleResult.hover(function over(e) {
410  $(".station-nav", this).fadeIn('normal');
411  }, function out(e) {
412  $(".station-nav", this).fadeOut(100);
413  });
414  }
415  $('.search-results', node).append(singleResult);
416 
417  $('.station-play', singleResult).click(function(e) {
418  e.stopPropagation();
419  e.preventDefault();
420  LastfmTuner.saveRecentStation(val);
421  LastfmTuner.svc.radioPlay(val.stationUrl);
422  });
423  $('.station-web', singleResult).click(function(e) {
424  e.stopPropagation();
425  e.preventDefault();
426  gBrowser.loadOneTab(val.url);
427  });
428 
429  singleResult.stationInfo = val;
430  singleResult.click(function(e) {
431  e.stopPropagation();
432  e.preventDefault();
433  onclick(singleResult);
434  });
435  });
436  },
437 
438  createDetailBlock: function(info, type) {
439  var playStr = LastfmTuner._strings.GetStringFromName(
440  "lastfm.radio.play");
441  var block = $("<div class='detail-view detail-view-" + type + "'>" +
442  "<img class='" + type + "-image' src='" + info.lImageUrl + "'/>" +
443  "<div class='detail-info-" + type + "'><h3>" + info.name + "</h3>" +
444  "<div class='detail-info-homepage'><a href=''>" +
445  "<img src='" + GLOBE_ICON + "'/>View station page" +
446  "</a></div>" +
447  "<div class='station-play-button'><a href='" + info.stationUrl +
448  "'><img src='" + RADIO_ICON_SMALL + "'/>" +
449  playStr + "</a></div>"
450  + "</div></div>");
451 
452  $(".station-play-button", block).click(function(e) {
453  e.stopPropagation();
454  e.preventDefault();
455  LastfmTuner.saveRecentStation(info);
456  LastfmTuner.svc.radioPlay(info.stationUrl);
457  });
458  $(".detail-info-homepage", block).click(function(e) {
459  e.stopPropagation();
460  e.preventDefault();
461  gBrowser.loadOneTab(info.url);
462  });
463 
464  if (!info.lImageUrl) {
465  LastfmTuner.svc.apiCall('artist.getInfo', {
466  limit: 20,
467  artist: info.name,
468  }, function response(success, xml) {
469  var results = LastfmTuner.collectResults(success, xml,
470  "artist", 1);
471  if (results == null) {
472  dump("artist.getInfo failed\n");
473  return;
474  }
475  dump("setting image to: " + results[0].lImageUrl + "\n");
476  $("img." + type + "-image", block)[0].src =
477  results[0].lImageUrl;
478  });
479  }
480 
481  return block;
482  },
483 
484  drawSingleArtist: function(info) {
485  var artistDetail = LastfmTuner._strings.GetStringFromName(
486  "lastfm.radio.artist.detail");
487  $('#explorer').empty();
488  $('#explorer').append("<h2 class='title'>" + artistDetail + "</h2>");
489 
490  // we got passed a station object, wrap it into a jQuery element
491  // and render it
492  var detailBlock = LastfmTuner.createDetailBlock(info, "artist");
493  $('#explorer').append(detailBlock);
494  $('#explorer').append("<div style='clear:left;' />");
495 
496  $('#explorer').append("<div id='tags'>");
497  var tagsDiv = $('#explorer > #tags');
498  tagsDiv.hide();
499  $('#explorer').append("<div id='artists'>");
500  var artistsDiv = $('#explorer > #artists');
501  artistsDiv.hide();
502  $('#explorer').append("<div id='fans'>");
503  var fansDiv = $('#explorer > #fans');
504  fansDiv.hide();
505 
506  var tagsStr = LastfmTuner._strings.GetStringFromName(
507  "lastfm.radio.artist.tags");
508  tagsDiv.append("<h3 class='subtitle'>" + tagsStr + "</h3>");
509  tagsDiv.append("<div class='results'>");
510 
511  var similarStr = LastfmTuner._strings.GetStringFromName(
512  "lastfm.radio.similar.artists");
513  artistsDiv.append("<h3 class='subtitle'>" + similarStr + "</h3>");
514  artistsDiv.append("<div class='results'>");
515 
516  var fansStr = LastfmTuner._strings.GetStringFromName(
517  "lastfm.radio.fans");
518  fansDiv.append("<h3 class='subtitle'>" + fansStr + "</h3>");
519  fansDiv.append("<div class='results'>");
520 
521  LastfmTuner.svc.apiCall('artist.gettoptags', {
522  limit: 20,
523  artist: info.name,
524  }, function response(success, xml) {
525  var results = LastfmTuner.collectResults(success, xml, "tag",
526  DISPLAY_RELATED_TAGS_LIMIT);
527  if (results == null) {
528  dump("collect artist top tags failed\n");
529  return;
530  }
531  LastfmTuner.drawMultipleResults(results, "tag", "s", 9,
532  $('.results', tagsDiv), function(station) {
533  LastfmTuner.drawSingleTag(station.stationInfo);
534  });
535  tagsDiv.append("<div style='clear:left;' />");
536  tagsDiv.fadeIn('slow');
537  $(window).resize();
538  });
539 
540  LastfmTuner.svc.apiCall('artist.getsimilar', {
541  limit: 20,
542  artist: info.name,
543  }, function response(success, xml) {
544  var results = LastfmTuner.collectResults(success, xml, "artist",
545  DISPLAY_RELATED_ARTISTS_LIMIT);
546  if (results == null) {
547  dump("collect artist similar artists failed\n");
548  return;
549  }
550  LastfmTuner.drawMultipleResults(results, "artist", "l", 9,
551  $('.results', artistsDiv), function(station) {
552  LastfmTuner.drawSingleArtist(station.stationInfo);
553  });
554  artistsDiv.append("<div style='clear:left;' />");
555  artistsDiv.fadeIn('slow');
556  $(window).resize();
557  });
558 
559  LastfmTuner.svc.apiCall('artist.getTopFans', {
560  limit: 20,
561  artist: info.name,
562  }, function response(success, xml) {
563  var results = LastfmTuner.collectResults(success, xml, "user",
564  DISPLAY_TOP_FANS_LIMIT);
565  if (results == null) {
566  dump("collect artist top fans failed\n");
567  return;
568  }
569  LastfmTuner.drawMultipleResults(results, "artist", "l", 9,
570  $('.results', fansDiv), function(station) {
571  LastfmTuner.drawSingleUser(station.stationInfo);
572  });
573  fansDiv.append("<div style='clear:left;' />");
574  fansDiv.fadeIn('slow');
575  $(window).resize();
576  });
577  },
578 
579  drawSingleTag: function(info) {
580  var tagDetail = LastfmTuner._strings.GetStringFromName(
581  "lastfm.radio.tag.detail");
582  $('#explorer').empty();
583  $('#explorer').append("<h2 class='title'>" + tagDetail + "</h2>");
584 
585  var detailBlock = LastfmTuner.createDetailBlock(info, "tag");
586  $('#explorer').append(detailBlock);
587 
588  $('#explorer').append("<div style='clear:left;' />");
589 
590  $('#explorer').append("<div id='tags'>");
591  var tagsDiv = $('#explorer > #tags');
592  tagsDiv.hide();
593  $('#explorer').append("<div id='artists'>");
594  var artistsDiv = $('#explorer > #artists');
595  artistsDiv.hide();
596 
597  var similarTags = LastfmTuner._strings.GetStringFromName(
598  "lastfm.radio.similar.tags");
599  tagsDiv.append("<h3 class='subtitle'>" + similarTags + "</h3>");
600  tagsDiv.append("<div class='results'>");
601 
602  var tagArtists = LastfmTuner._strings.GetStringFromName(
603  "lastfm.radio.tag.artists");
604  artistsDiv.append("<h3 class='subtitle'>" + tagArtists + "</h3>");
605  artistsDiv.append("<div class='results'>");
606 
607  LastfmTuner.svc.apiCall('tag.getsimilar', {
608  limit: 20,
609  tag: info.name,
610  }, function response(success, xml) {
611  var results = LastfmTuner.collectResults(success, xml, "tag",
612  DISPLAY_RELATED_TAGS_LIMIT);
613  if (results == null) {
614  dump("collect tag similar tags failed\n");
615  return;
616  }
617 
618  LastfmTuner.drawMultipleResults(results, "tag", "s", 9,
619  $('.results', tagsDiv), function(station) {
620  LastfmTuner.drawSingleTag(station.stationInfo);
621  });
622  tagsDiv.append("<div style='clear:left;' />");
623  tagsDiv.fadeIn('slow');
624  $(window).resize();
625  });
626 
627  LastfmTuner.svc.apiCall('tag.gettopartists', {
628  limit: 20,
629  tag: info.name,
630  }, function response(success, xml) {
631  var results = LastfmTuner.collectResults(success, xml, "artist",
632  DISPLAY_RELATED_ARTISTS_LIMIT);
633  if (results == null) {
634  dump("collect tag tagged artists failed\n");
635  return;
636  }
637 
638  LastfmTuner.drawMultipleResults(results, "artist", "l", 9,
639  $('.results', artistsDiv), function(station) {
640  LastfmTuner.drawSingleArtist(station.stationInfo);
641  });
642  artistsDiv.append("<div style='clear:left;' />");
643  artistsDiv.fadeIn('slow');
644  $(window).resize();
645  });
646  },
647 
648  drawSingleUser: function(info) {
649  var userDetail = LastfmTuner._strings.GetStringFromName(
650  "lastfm.radio.user.detail");
651  $('#explorer').empty();
652  $('#explorer').append("<h2 class='title'>" + userDetail + "</h2>");
653 
654  var info;
655  var detailBlock = LastfmTuner.createDetailBlock(info, "user");
656  $('#explorer').append(detailBlock);
657 
658  $('#explorer').append("<div style='clear:left;' />");
659 
660  $('#explorer').append("<div id='tags'>");
661  var tagsDiv = $('#explorer > #tags');
662  tagsDiv.hide();
663  $('#explorer').append("<div id='artists'>");
664  var artistsDiv = $('#explorer > #artists');
665  artistsDiv.hide();
666 
667  var topTags = LastfmTuner._strings.GetStringFromName(
668  "lastfm.radio.tags.top");
669  var topArtists = LastfmTuner._strings.GetStringFromName(
670  "lastfm.radio.artists.top");
671  tagsDiv.append("<h3 class='subtitle'>" + topTags + "</h3>");
672  tagsDiv.append("<div class='results'>");
673 
674  artistsDiv.append("<h3 class='subtitle'>" + topArtists + "</h3>");
675  artistsDiv.append("<div class='results'>");
676 
677  LastfmTuner.svc.apiCall('user.getTopTags', {
678  limit: 20,
679  user: info.name
680  }, function response(success, xml) {
681  var results = LastfmTuner.collectResults(success, xml, "tag",
682  DISPLAY_RELATED_TAGS_LIMIT);
683  if (results == null) {
684  dump("collect user top tags failed\n");
685  return;
686  }
687 
688  LastfmTuner.drawMultipleResults(results, "tag", "s", 9,
689  $('.results', tagsDiv), function(station) {
690  LastfmTuner.drawSingleTag(station.stationInfo);
691  });
692  tagsDiv.append("<div style='clear:left;' />");
693  tagsDiv.fadeIn('slow');
694  $(window).resize();
695  });
696 
697  LastfmTuner.svc.apiCall('user.getTopArtists', {
698  limit: 20,
699  user: info.name
700  }, function response(success, xml) {
701  var results = LastfmTuner.collectResults(success, xml, "artist",
702  DISPLAY_RELATED_ARTISTS_LIMIT);
703  if (results == null) {
704  dump("collect user top artists failed\n");
705  return;
706  }
707 
708  LastfmTuner.drawMultipleResults(results, "artist", "l", 9,
709  $('.results', artistsDiv), function(station) {
710  LastfmTuner.drawSingleArtist(station.stationInfo);
711  });
712  artistsDiv.append("<div style='clear:left;' />");
713  artistsDiv.fadeIn('slow');
714  $(window).resize();
715  });
716  },
717 
718  saveRecentStation: function(thisStation) {
719  var prevIdx = -1;
720 
721  for (var i=0; i<LastfmTuner.recentStations.length; i++) {
722  if (LastfmTuner.recentStations[i].stationUrl == thisStation.stationUrl) {
723  prevIdx = i;
724  break;
725  }
726  }
727  if (prevIdx > -1) {
728  dump("duplicate station found @ " + prevIdx + "\n");
729  LastfmTuner.recentStations.splice(prevIdx, 1);
730  }
731  LastfmTuner.recentStations.push(thisStation);
732  Application.prefs.setValue("extensions.lastfm.recent.stations",
733  LastfmTuner.jsonSvc.encode(LastfmTuner.recentStations));
734  },
735 
736  setHeaderDisplay: function() {
737  var paintBlack = Application.prefs.getValue("extensions.lastfm.header",
738  false);
739  var hTopEl = document.getElementById("header-top");
740  $("#lastfm-header-style").empty();
741  if (paintBlack) {
742  // Set the background to Black
743  $("#lastfm-header-style").append("Simply Red");
744  hTopEl.setAttribute("paintblack", "true");
745  } else {
746  $("#lastfm-header-style").append("Paint it Black");
747  hTopEl.setAttribute("paintblack", "false");
748  }
749  },
750 
751  toggleHeaderDisplay: function() {
752  var paintBlack = Application.prefs.getValue("extensions.lastfm.header",
753  false);
754  Application.prefs.setValue("extensions.lastfm.header", !paintBlack);
755  this.setHeaderDisplay();
756  },
757 
758  observe: function(subject, topic, data) {
759  if (subject instanceof Components.interfaces.nsIPrefBranch) {
760  if (data == "recent.stations") {
761  dump("recent stations changed!\n");
762  LastfmTuner.populateBox("nav-recent-stations",
763  LastfmTuner.dataRecentStations);
764  }
765  }
766  },
767 
768  /*
769  * Functions for returning data for populating search boxes
770  */
771  dataRecentStations: function(populateCallback) {
772  LastfmTuner.recentStations =
773  LastfmTuner.jsonSvc.decode(Application.prefs.getValue(
774  "extensions.lastfm.recent.stations", "[]"));
775  while (LastfmTuner.recentStations.length > DISPLAY_RECENT_STATIONS_LIMIT)
776  LastfmTuner.recentStations.shift();
777  populateCallback(LastfmTuner.recentStations);
778  },
779 
780  dataRecArtists: function(populateCallback) {
781  LastfmTuner.svc.apiCall('user.getRecommendedArtists', {
782  }, function response(success, xml) {
783  var results = LastfmTuner.collectResults(success, xml, "artist");
784  if (results == null) {
785  dump("collect recommended artists failed\n");
786  return;
787  }
788  populateCallback(results);
789  });
790  },
791 
792  dataTopArtists: function(populateCallback) {
793  LastfmTuner.svc.apiCall('user.getTopArtists', {
794  user: LastfmTuner.svc.username
795  }, function response(success, xml) {
796  var results = LastfmTuner.collectResults(success, xml, "artist");
797  if (results == null) {
798  dump("collect recommended artists failed\n");
799  return;
800  }
801  populateCallback(results);
802  });
803  },
804 
805  dataTopTags: function(populateCallback) {
806  LastfmTuner.svc.apiCall('user.getTopTags', {
807  user: LastfmTuner.svc.username
808  }, function response(success, xml) {
809  var results = LastfmTuner.collectResults(success, xml, "tag");
810  if (results == null) {
811  dump("collect top tags failed\n");
812  return;
813  }
814  populateCallback(results);
815  });
816  },
817 
818  dataMyFriends: function(populateCallback) {
819  LastfmTuner.svc.apiCall('user.getFriends', {
820  user: LastfmTuner.svc.username
821  }, function response(success, xml) {
822  var results = LastfmTuner.collectResults(success, xml, "user");
823  if (results == null) {
824  dump("collect my friends failed\n");
825  return;
826  }
827  populateCallback(results);
828  });
829  },
830 
831  dataMyNeighbours: function(populateCallback) {
832  LastfmTuner.svc.apiCall('user.getNeighbours', {
833  user: LastfmTuner.svc.username
834  }, function response(success, xml) {
835  var results = LastfmTuner.collectResults(success, xml, "user");
836  if (results == null) {
837  dump("collect my neighbours failed\n");
838  return;
839  }
840  populateCallback(results);
841  });
842  },
843 
844  dataSBCollect: function(primary, secondary, type, callback) {
845  var lib = LibraryUtils.mainLibrary;
846  var collectResults = lib.collectDistinctValues(primary,
847  Ci.sbILibraryStatistics.COLLECT_SUM, secondary, false, 30);
848  var results = new Array();
849  for (var i=0; i<collectResults.length; i++) {
850  var s = collectResults.queryElementAt(i, Ci.nsIVariant)
851  .replace(/&/g, "&amp;").replace(/>/g, "gt;")
852  .replace(/</g, "&lt;").replace(/"/g, "&quot;");
853  var url = encodeURIComponent(s).replace(/'/g, "%27");
854  results.push({
855  type: type,
856  name: s,
857  url: "http://www.last.fm/" + type + "/" + url,
858  stationUrl: "lastfm://" + type + "/" + url
859  });
860  }
861  callback(results);
862  },
863 
865  LastfmTuner.dataSBCollect(SBProperties.artistName,
866  SBProperties.playCount, "artist", populateCallback);
867  },
868  dataSBHighestRatedArtists: function(populateCallback) {
869  LastfmTuner.dataSBCollect(SBProperties.artistName,
870  SBProperties.rating, "artist", populateCallback);
871  },
872  dataSBGenres: function(populateCallback) {
873  LastfmTuner.dataSBCollect(SBProperties.genre,
874  SBProperties.playCount, "tag", populateCallback);
875  },
876 
877  populateBox: function(elementId, dataCallback, limit) {
878  var resultsEl = $('#' + elementId + "-results");
879  resultsEl.empty();
880  dataCallback(function(results) {
881  if (results == null || results.length == 0)
882  return;
883  results.forEach(function(val, i, arr) {
884  if ((!limit && (i >= LIMIT_NAV_RESULTS)) ||
885  (limit && (i >= limit)))
886  return;
887  var rowClass = "row-even";
888  if (i % 2)
889  rowClass = "row-odd";
890  var playStr = LastfmTuner._strings.GetStringFromName(
891  "lastfm.radio.play");
892  var stationEl = $(
893  "<div class='nav-station " + rowClass + "'>" +
894  "<div class='station-play-button'><a href='" +
895  val.stationUrl + "'><img src='" + RADIO_ICON_SMALL +
896  "'/>" + playStr + "</a></div>" +
897  "<img src ='chrome://sb-lastfm/skin/" + val.type +
898  ".png' class='icon-type' />" + val.name + "</div>");
899  $(".station-play-button", stationEl).click(function(e) {
900  e.stopPropagation();
901  e.preventDefault();
902  dump("Saving recent station\n");
903  LastfmTuner.saveRecentStation(val);
904  LastfmTuner.svc.radioPlay(val.stationUrl);
905  });
906  stationEl.click(function(e) {
907  // Load this station in the explorer view
908  dump("type: " + val.type + "\n");
909  switch (val.type) {
910  case "artist":
911  LastfmTuner.drawSingleArtist(val);
912  break;
913  case "tag":
914  LastfmTuner.drawSingleTag(val);
915  break;
916  case "user":
917  LastfmTuner.drawSingleUser(val);
918  break;
919  default:
920  // Load the station detail page in a tab
921  gBrowser.loadOneTab(val.url);
922  }
923  });
924  stationEl.hover(function(e) {
925  this.oldClass = this.className;
926  this.className += " row-open";
927  }, function(e) {
928  this.className = this.oldClass;
929  });
930  resultsEl.append(stationEl);
931  });
932  });
933  }
934 }
935 
936 // Adjust height of explorer area
937 $(window).resize(function(e) {
938  var bodyHeight = $('body')[0].scrollHeight;
939  var height = bodyHeight - $('#header')[0].scrollHeight;
940  var height2 = $('#left-content')[0].scrollHeight;
941  //dump("Height: " + height + " or " + height2 + "\n");
942  if (height2 > height)
943  height = height2;
944  $('#right-nav').css({"min-height":height});
945 
946  height = $('#content')[0].scrollHeight + $('#header')[0].scrollHeight;
947  $(".wrapper-box").css({"height":bodyHeight, "max-height":bodyHeight});
948  $("#login-page").css({"min-height":height});
949  $("#subscriber-page").css({"min-height":height});
950 });
951 
952 $(document).ready(function() {
953  LastfmTuner.init();
954 
955  // Hide the nav bar entirely
956  $("#right-nav-last-fm").hide();
957 
958  // Hide the user photo
959  $("#user-profile").hide();
960 
961  // Hide the results blocks
962  $('.nav-results:not(.section-open)').hide();
963 
964  // Setup hovers for the user-stations box
965  $('#nav-user-stations-results .nav-station').hover(function over(e) {
966  this.oldClass = this.className;
967  this.className += " row-open";
968  }, function(e) {
969  this.className = this.oldClass;
970  });
971 
972  // Setup the search box
973  $('#search-box').focus(function() {
974  $(this).css({"color": "#555"});
975  this.value = "";
976  });
977  // Add click handlers for accordian riht hand nav
978  $('#right-nav h3.nav-stations').click(function() {
979  var resultsId = this.parentNode.parentNode.id + "-results";
980  $('.nav-results:not(#'+resultsId+')').hide('fast');
981  if ($('#' + resultsId).is(':hidden')) {
982  $('#' + resultsId).slideDown('fast');
983  this.className = "nav-stations section-open";
984  } else {
985  $('#' + resultsId).hide('fast');
986  this.className = "nav-stations";
987  }
988  $(window).resize();
989  });
990 
991  // Locate the country we're coming from so we can update the
992  // start-artists
993  $("#start-artists").hide();
994  $("#start-tags").hide();
995  $.get("http://api.hostip.info/", {}, function(data) {
996  LastfmTuner.myCountry =
997  data.getElementsByTagName("countryName")[0].textContent;
998  //dump("Country: " + LastfmTuner.myCountry + "\n");
999  if (LastfmTuner.myCountry == "(Unknown Country?)")
1000  LastfmTuner.myCountry = "UNITED STATES";
1001  LastfmTuner.svc.apiCall('geo.getTopArtists', {
1002  country : LastfmTuner.myCountry
1003  }, function response(success, xml) {
1004  var results = LastfmTuner.collectResults(success, xml, "artist");
1005  if (results == null) {
1006  dump("collect geo top artists failed\n");
1007  return;
1008  }
1009 
1010  var e = $("#start-artists");
1011  LastfmTuner.drawMultipleResults(results, "artist", "l", 12, e,
1012  function(station) {
1013  LastfmTuner.drawSingleArtist(station.stationInfo);
1014  });
1015  e.slideDown("slow", function() {
1016  $(window).resize()
1017  });
1018  });
1019  }, "xml");
1020 
1021  LastfmTuner.svc.apiCall('tag.getTopTags', {},
1022  function response(success, xml) {
1023  var results = LastfmTuner.collectResults(success, xml, "tag");
1024  if (results == null) {
1025  dump("collect last.fm top tags failed\n");
1026  return;
1027  }
1028 
1029  var e = $("#start-tags");
1030  LastfmTuner.drawMultipleResults(results, "tag", "s", 12, e,
1031  function(station) {
1032  LastfmTuner.drawSingleTag(station.stationInfo);
1033  });
1034  e.slideDown("slow", function() {
1035  $(window).resize();
1036  });
1037  });
1038 
1039  $("#lastfm-user-info").click(function(e) {
1040  e.preventDefault();
1041  e.stopPropagation();
1042  gBrowser.loadOneTab(LastfmTuner.profileurl);
1043  });
1044  $("#lastfm-user-image").click(function(e) {
1045  e.preventDefault();
1046  e.stopPropagation();
1047  gBrowser.loadOneTab(LastfmTuner.profileurl);
1048  });
1049 
1050 
1051  // Update the login state
1052  LastfmTuner.onLoggedInStateChanged();
1053  if (LastfmTuner.svc.loggedIn) {
1054  LastfmTuner.onProfileUpdated();
1055  //LastfmTuner.onLoginSucceeded();
1056  }
1057 
1058  if (LastfmTuner.svc.sk)
1059  LastfmTuner.onAuthorisationSuccess();
1060 
1061  if (LastfmTuner.svc.loggedIn) {
1062  // Focus the search box
1063  $("#search-box")[0].focus();
1064  }
1065 });
1066 
1067 window.addEventListener("unload", LastfmTuner.fini, false);
const Cu
const Cc
function for each(var file in gFilesToClose)
var Application
Definition: sbAboutDRM.js:37
menuItem id
Definition: FeedWriter.js:971
sbOSDControlService prototype className
populateBox limit
Definition: tuner2.js:877
populateBox dataCallback
Definition: tuner2.js:875
let window
var getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('Songbird SBProperties artist
Definition: tuner2.js:40
_window init
Definition: FeedWriter.js:1144
gTestRoot append("_tests")
var getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('Songbird dataSBMostPlayedArtists
Definition: tuner2.js:40
function search(aFolderId, aSearchStr, aExpectedScopeButtonId)
Element Properties href
this _dialogInput val(dateText)
grep callback
return null
Definition: FeedWriter.js:1143
_updateDatepicker height
var getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('Songbird SBProperties populateCallback
Definition: tuner2.js:40
let node
function url(spec)
countRef value
Definition: FeedWriter.js:1423
return aWindow document documentElement getAttribute(aAttribute)||dimension
observe topic
Definition: FeedWriter.js:1326
const Ci
Javascript wrappers for common library tasks.
window resize(function(e){var bodyHeight=$('body')[0].scrollHeight;var height=bodyHeight-$('#header')[0].scrollHeight;var height2=$('#left-content')[0].scrollHeight;if(height2 > height) height=height2;$('#right-nav').css({"min-height":height});height=$('#content')[0].scrollHeight+$('#header')[0].scrollHeight;$(".wrapper-box").css({"height":bodyHeight,"max-height":bodyHeight});$("#login-page").css({"min-height":height});$("#subscriber-page").css({"min-height":height});})
dataSBGenres SBProperties tag
Definition: tuner2.js:871
this _dialogInput css('left', this._pos[0]+'px').css('top'
observe data
Definition: FeedWriter.js:1329
let< body >< buttononblur="this.parentNode.removeChild(this);">< script > document body firstChild focus()
_getSelectedPageStyle s i
if(typeof(Cc)=="undefined") var Cc
var getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('Songbird LastfmTuner
Definition: tuner2.js:40
sbDeviceFirmwareAutoCheckForUpdate prototype observe