Monday, December 5, 2011

ScrobbleSmurf


// ==UserScript==
// @name           SrobbleSmurf
// @namespace      scrobble
// @description    Scrobble songs from YouTube.
// @include        http://youtube.com/watch?*v=*
// @include        http://www.youtube.com/watch?*v=*
// @include        http://youtube.com/watch#!*v=*
// @include        http://www.youtube.com/watch#!*v=*
// Version 1.1.2
// ==/UserScript==
/* You can contact me on Twitter @DDaanV or Last.FM (DDaan90).
 * - Don't steal all of my code and say it's yours. 
 * - You may steal parts of my code. Credits are not required. 
 * - Suggestions and improvements are welcome. 
 * - This code is free, when you take parts of my code expect it will remain free.
 */
/* TODO's: 
 * - Create more reliable timer (use system time).
 * - Use JSON parser instead of 'eval' which should increase performance.
 * - Server-side: Attemp to swap artist and title when scrobbling failed.
 * - Scrobble from YouTube user channels. (http://www.youtube.com/user/* && http://youtube.com/user/*)
 * - Better error handling. 
 */
var cosmicPanda = false;
var showTime = 0;
var scrobLength = -1;
var noScrobble = false;
var iTunesArtistAndTitleFound = false;

var scrobbleAutoCollapse = true;
var scrobblePercentage = 50;
var scrobbleEnabled = true;
var scrobbleFilter = "";

var apiKey = "870da3cecaf2a63062b474a93ace2285";
var lastFmAuthenticationUrl = "http://www.last.fm/api/auth";
var authenticationSessionUrl = "http://daan.hostei.com/lastfm/auth/getSession";
var scrobbleSongUrl = "http://daan.hostei.com/lastfm/scrobbleSong";
var altScrobbleSongUrl = "http://ddaan.nl/lastfm/scrobbleSong";
var youtubeApiUrl = "http://gdata.youtube.com/feeds/api/videos/";

//--General functions.
/**
 * Initialisation function, should be called only once when the document is loaded. 
 * The ScrobbleSmurf plug-in will be added to the YouTube page.
 */
function initialize() {
 try {
  localStorageEnabledCheck();
  fixVideoEmbedOpaqueness();
  loadSavedFormValues();
  cosmicPandaLayout();
  addStyle();
  addLastFmOptions();
  addLastFmButton();
  addMenuPop();
  activateLastFmButtons();
  var song = getSongInformation();
  fillSongInformation(song);
  videoApiRequest();
  
  if(!isLoggedIn()) {
   showLoginHideReset();
   tryGetAuthToken();
  } else {
   setUsernameSpan();
   hideLoginShowReset();
  }
 } catch (e) {
  console.log(e);
 }
}

/**
 * Shows a message in the ScrobbleSmurf menu.
 */
function menuAlert(text) {
 text = text.replace(/\n/gi, "<br/>");
 var scrobbCount = document.getElementById("scrobble-counter");
 var scrobbMessg = document.getElementById("scrobble-message");
 var scrobbMsg = document.getElementById("scrobble-msg");
 scrobbCount.style.display = "none";
 scrobbMessg.style.display = "block";
 scrobbMsg.innerHTML = text + ".";
}
//--Google Chrome compatibility functions.
/**
 * Alerts the user when the browser does not support HTML5 local storage.
 */
function localStorageEnabledCheck()
{
 var localStorageEnabled = window.localStorage;
 if(!localStorageEnabled) {
  alert("Your browser does not support HTML5 local storage.\n" +
   "This is required to use ScrobbleSmurf V1.1 and up.");
 }
}
/**
 * Adds wmode=opaque to which the video is embedded. 
 * Used to overlay the options in Google Chrome.
 */
function fixVideoEmbedOpaqueness()
{
  var wmodeParam = document.createElement("param");
  wmodeParam.setAttribute("name", "wmode");
  wmodeParam.setAttribute("value", "opaque");

  var div = document.getElementById("watch-player");
  var videoEmbed = div.getElementsByTagName("embed")[0];
  var parent = videoEmbed.parentNode;
  
  parent.removeChild(videoEmbed);
  
  videoEmbed.setAttribute("wmode", "opaque");
  videoEmbed.appendChild(wmodeParam);
  
  parent.appendChild(videoEmbed);
}

//--Functions for the additional menu pop up.
/**
 * Adds the more options pop up and background to the YouTube page. 
 * By default the pop up is hidden, to show it call the moreOptions method.
 */
function addMenuPop()
{
 var page = document.getElementById("page");
 var pop = document.createElement("div");
 pop.setAttribute("id", "lastfm-moreoptions-pop");
 pop.style.visibility = "hidden";
 pop.innerHTML = "<h2>More Last FM Options</h2>\n" + 
 "<form id=\"lastfm-moreoptions-form\">\n" +
 "<table class=\"lastfm-moreoptions-table\"><tr>\n" +
 " <td>Collapse ScrobbleSmurf menu</td>\n" +
 " <td><input name=\"lastfm-moreoptions-collapse\" type=\"radio\" value=\"collapse\">Collapse the menu by default.<br/>\n" + 
 " <input name=\"lastfm-moreoptions-collapse\" type=\"radio\" value=\"expand\">Expand the menu by default.</td>\n" +
 "</tr><tr>\n" +
 " <td>Scrobble percentage</td>\n" +
 " <td><select style=\"width:100%\" name=\"lastfm-moreoptions-percentage\">\n" +
 "  <option value=\"20\">20 percent</option>\n" +
 "  <option value=\"30\">30 percent</option>\n" +
 "  <option value=\"40\">40 percent</option>\n" +
 "  <option value=\"50\">50 percent</option>\n" +
 "  <option value=\"60\">60 percent</option>\n" +
 "  <option value=\"70\">70 percent</option>\n" +
 "  <option value=\"80\">80 percent</option>\n" +
 " </select></td>\n" +
 "</tr><tr>\n" +
 " <td>Words to remove<br/><i>(separate by semicolon)<i></td>\n" +
 " <td><input style=\"width:100%\" id=\"lastfm-moreoptions-filter\" name=\"lastfm-moreoptions-filter\" type=\"text\"></input></td>\n" +
 "</tr><tr>\n" +
 " <td>Enable all scrobbling</td>\n" +
 " <td><input name=\"lastfm-moreoptions-scrobble\" type=\"radio\" value=\"yes\">Yes, scrobble my songs to Last FM<br/>\n" + 
 " <input name=\"lastfm-moreoptions-scrobble\" type=\"radio\" value=\"no\">No, do not scrobble my songs</td>\n" +
 "</tr></table>\n" +
 "</form>\n" +
 "<div class=\"lastfm-moreoptions-controls\">\n" + 
 " <button class=\"yt-uix-button yt-uix-tooltip\" id=\"lastfm-moreoptions-ok\" title=\"Save changes\"><span class=\"yt-uix-button-content\">Save</span></button>\n" +
 " <button class=\"yt-uix-button yt-uix-tooltip\" id=\"lastfm-moreoptions-cancel\" title=\"Discard changes\" style=\"margin-left: 14px;\"><span class=\"yt-uix-button-content\">Cancel</span></button>\n" +
 "</div>\n"; 
 page.appendChild(pop);
 addMenuBack(pop);
 centerPopup(pop);
 
 setDefaultSelectValue("lastfm-moreoptions-percentage", scrobblePercentage);
 activatePopupControls();
}
/**
 * Add the more options pop up background to the YouTube page.
 */
function addMenuBack(menuElement)
{
 var overlay = document.createElement("div");
 overlay.setAttribute("id", "lastfm-moreoptions-back");
 overlay.style.visibility = "hidden";
 menuElement.parentNode.appendChild(overlay);
 
 var body = document.body, html = document.documentElement;
 var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
 overlay.style.height = height + "px";
}
/**
 * Attemps to center the more options pop up.
 */
function centerPopup(popup) {
 var windowWidth = document.documentElement.clientWidth;
 var windowHeight = document.documentElement.clientHeight;
 
 var popupWidth = parseInt(popup.clientWidth);
 var popupHeight = parseInt(popup.clientHeight);
 
 popup.style.position = "absolute";
 var top = windowHeight/2-popupHeight/2;
 var left = windowWidth/2-popupWidth/2;
 popup.style.top = (top > 0 ? top : 0) + "px";
 popup.style.left = (left > 0 ? left : 0) + "px";
}
/**
 * Attemps to center the more options pop up.
 */
function activatePopupControls()
{
 var okButton = document.getElementById("lastfm-moreoptions-ok");
 var cancelButton = document.getElementById("lastfm-moreoptions-cancel");
 
 okButton.addEventListener("click", saveCurrentForm, false);
 cancelButton.addEventListener("click", function() { moreOptions(true); }, false);
}
/**
 * Saves the currently selected values from the more options menu pop up to the user's hard disk.
 */
function saveCurrentForm()
{
 var sform = document.getElementById("lastfm-moreoptions-form");
 
 var collapse = getSelectedRadioButton("lastfm-moreoptions-collapse");
 var percentage = sform.elements["lastfm-moreoptions-percentage"].value;
 var filter = sform.elements["lastfm-moreoptions-filter"].value;
 var enable = getSelectedRadioButton("lastfm-moreoptions-scrobble");
 
 localStorage.setItem("lastfmExpand", (collapse != "expand"));
 localStorage.setItem("lastfmPercentage", percentage);
 localStorage.setItem("lastfmFilter", filter);
 localStorage.setItem("lastfmScrobble", enable != "no");
  
 moreOptions(true); 
 loadSavedFormValues();
}
/**
 * Loads values from the more options menu pop up the user saved to it's hard disk. 
 */
function loadSavedFormValues()
{
 scrobbleAutoCollapse = localStorage.getItem("lastfmExpand");
 scrobblePercentage = localStorage.getItem("lastfmPercentage");
 scrobbleFilter = localStorage.getItem("lastfmFilter");
 scrobbleEnabled = localStorage.getItem("lastfmScrobble");
}
//--Functions to get additional video information from the YouTube API.
/**
 * Updates the cosmicPanda variable which is a different version of the YouTube layout.
 * Different layout requires different handling.
 */
function cosmicPandaLayout() {
 var r = document.getElementById("watch-frame-bottom");
 if(r != null) {
  cosmicPanda = true;
 }
}
/**
 * Gets the current YouTube video ID from the browser URL.
 */
function getYouTubeVideoId() {
 var regex = /(\?|&)v=[^\?&#]*/gi;
 var matches = document.URL.match(regex);
 if(matches == null) {
  return null;
 }
 var videoCode = matches[0].substring(3);
 return videoCode;
}
/**
 * Uses the YouTube API to get more information from the current video.
 */
function videoApiRequest() {
 var vidId = getYouTubeVideoId();
 if(vidId == null) {
  return;
 }
 GM_xmlhttpRequest({
  method: "GET",
  url: youtubeApiUrl + vidId + "?v=2&alt=jsonc",
  headers: {
   "Accept": "application/json"
  },
  onload: videoApiResponse,
  onerror: function() { "menuAlert(\"Could not connect \nto YouTube API.\")" }
 });
}
/**
 * Handles data returned from the YouTube API which provides more data from the video.
 */
function videoApiResponse(response) {
 var jsonObject = eval("(" + response.responseText + ")");
 var category = jsonObject.data.category.toLowerCase();
 if(countOccurencesInString(category, "music") < 1) {
  noScrobble = true;
  menuAlert("No music video");
  return;
 }
 
 if(scrobbleEnabled !== true && scrobbleEnabled !== "true") {
  dontScrobble();
 }
 
 scrobLength = Math.round(jsonObject.data.duration / (100 / scrobblePercentage) );
 timePlus();
 
 if(!iTunesArtistAndTitleFound) {
  var vidTitle = jsonObject.data.title;
  if(filterWords != null)
  {
   var filterWords = scrobbleFilter.split(";");
   
   for(word in filterWords) {
    var escapedFilterWords = escapeAllRegexSpecialChars(filterWords[word].trim());
    var filterRegex = new RegExp(escapedFilterWords, "gi");
    vidTitle = vidTitle.replace(filterRegex, "");
   }
  }
  
  var song = tryStripSongFromTitle(vidTitle);
  fillSongInformation(song);
 }
}
/**
 * Escapes all characters with a special meaning in Regular Expressions.
 */
function escapeAllRegexSpecialChars(regexString)
{
 var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\'
    ];
    var regex = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'g'
    );
 
 regexString= regexString.replace(regex, '\\$1'); 
 return regexString;
}
//--Scrobbling functions.
/**
 * Adds one to timer and updates the textspans. When the timeLeft is 0 (or less the song will be scrobbled).
 */
function timePlus() {
 showTime++;
 var timeLeft = scrobLength - showTime;
 
 var timeSpan = document.getElementById("scrobble-time");
 timeSpan.innerHTML = timeLeft;
 
 if(timeLeft > 0) {
  if(!noScrobble) {
   setTimeout(timePlus, 1000);
  }
 } else {
  scrobbleSong();
 }
}
/**
 * Srobbles a song using the values from the two textinput's from the form.
 */
function scrobbleSong() {
 var artist = document.getElementById("lastfm-artist").value;
 var title = document.getElementById("lastfm-title").value;
 if(artist == "" || title == "") {
  menuAlert("Insufficient artist \nand title information");
  return;
 }

 if(!isLoggedIn())
 {
  menuAlert("Please authenticate \nbefore scrobbling");
 }
 else
 {
  var user = getUserCredentials();
  var timestamp = Math.round(new Date().getTime()/1000.0);
  
  var args = "?artist=" + encodeURIComponent(artist) + "&sk=" + user.sessionkey + 
  "&timestamp=" + timestamp + "&track=" + encodeURIComponent(title);
  
  menuAlert("Scrobbling song");
   
  GM_xmlhttpRequest({
   method: "GET",
   url: altScrobbleSongUrl + args,
   onload: scrobbleFeedback,
   onerror: function() {
    GM_xmlhttpRequest({
     method: "GET",
     url: scrobbleSongUrl + args,
     onload: scrobbleFeedback,
     onerror: function() {
      menuAlert("Scrobbling failed");
     }
    });
   }
  });
 }
}
/**
 * Show the user a response to their Scrobble attempt.
 */
function scrobbleFeedback(response) {
 var text;
 if(countOccurencesInString(response.responseText, "\r?\n") > 0) {
  //Split the response, since my hosting puts in some spam.
  text = response.responseText.split(/\r?\n/gim)[0].replace(/#/g, "");
 } else {
  text = response.responseText;
 }
 var jsonObject = eval("(" + text + ")");
 
 if(jsonObject.error != null) {
  menuAlert("Error connecting to Last.FM.\n" + 
  "Error code: " + jsonObject.error + "\n" +
  "Message: " + jsonObject.message + ".");
 } else {
  var artist = jsonObject.scrobbles.scrobble.artist.text;
  var title = jsonObject.scrobbles.scrobble.track.text;
  menuAlert("Scrobbled song\nArtist: " + artist + "\nTitle: " + title);
 }
}
//--Login functions.
/**
 * Attempts to get a Last FM token from the URL. If so authenticate the user.
 */
function tryGetAuthToken() {
 var url = document.URL;
 var tokenRegex = /(\?|&)token=[0-9a-fA-F]{32}/gi;
 var matches = url.match(tokenRegex);
 if(matches == null) {
  return;
 }
 var rawToken = matches[0];
 var token = rawToken.substring(7); //7, based on '?' or '&' and 'token='.
 GM_xmlhttpRequest({
  method: "GET",
  url: authenticationSessionUrl + "?token=" + token,
  headers: {
   "Accept": "text/html" //My hosting puts in html spam
  },
  onload: getSessionKey
 });
}
/**
 * Gets a Last FM session key and store it for later reference.
 */
function getSessionKey(response) {
 //Split the response, since my hosting puts in some spam.
 var text = response.responseText.split(/\r?\n/gim)[0];
 var jsonObject = eval("(" + text + ")");
 
 if(jsonObject.error != null) {
  menuAlert("Error connecting to Last.FM.\n" + 
  "Error code: " + jsonObject.error + "\n" +
  "Message: " + jsonObject.message + ".");
 } else {
  localStorage.setItem("lastfmUsername", jsonObject.session.name);
  localStorage.setItem("lastfmSessionkey", jsonObject.session.key);
  
  setUsernameSpan();
  hideLoginShowReset();
 }
}
/**
 * Check whether user credentials are stored or not.
 */
function isLoggedIn() {
 var username = localStorage.getItem("lastfmUsername");
 var sessionk = localStorage.getItem("lastfmSessionkey");
 if(username == null || sessionk == null) {
  return false;
 }
 return true;
}
/**
 * Gets the user's stored credentials.
 */
function getUserCredentials() {
 var user = new Object();
 user.username = localStorage.getItem("lastfmUsername");
 user.sessionkey = localStorage.getItem("lastfmSessionkey");
 return user;
}
/**
 * Fills in the user's username on the Last FM form.
 */
function setUsernameSpan() {
 var usernameSpan = document.getElementById("lastfm-username");
 usernameSpan.innerHTML = getUserCredentials().username;
}
/**
 * Hides the 'login'-form, shows the 'reset login'-form
 */
function hideLoginShowReset() {
 var reset = document.getElementById("lastfm-options-resetlogin");
 var login = document.getElementById("lastfm-options-login");
 login.style.display = "none";
 reset.style.display = "block";
}
/**
 * Shows the 'login'-form, hides the 'reset login'-form
 */
function showLoginHideReset() {
 var reset = document.getElementById("lastfm-options-resetlogin");
 var login = document.getElementById("lastfm-options-login");
 reset.style.display = "none";
 login.style.display = "block";
}
//--Functions to edit the YouTube lay-out.
/**
 * Adds CSS style to the page used by this plug in.
 */
function addStyle() {
 var head = document.getElementsByTagName("head")[0];
 var style = document.createElement("style");
 head.appendChild(style);
 style.setAttribute("type", "text/css");
 style.innerHTML = "#masthead-lastfm { border: 1px solid #CCC; background: #F6F6F6; }\n" +
 "#lastfm-container { margin: 0 auto; width: 970px; }\n" +
 "ul#lastfm-options li { height: 90px; float: left; margin: 8px 0px; padding: 0px 24px; border-right: 1px solid #CCCCCC; }\n" + 
 "ul#lastfm-options p { padding-left: 1px; }\n" +
 "#lastfm-moreoptions { margin-bottom: 6px; }\n" +
 "#lastfm-moreoptions-pop { height:296px; width:432px; background:#FFF; border:2px solid #CCC; z-index:4; padding:12px; font-size:13px; }\n" +
 "#lastfm-moreoptions-back { position:absolute; height:100%; width:100%; top:0; left:0; background:#000; border:1px solid #333; z-index:3; opacity: 0.6; }\n" + 
 ".lastfm-moreoptions-table { border-collapse:collapse; }\n" + 
 ".lastfm-moreoptions-table td { border-bottom:1px solid #EEE; padding:8px 6px 10px; }\n" +
 ".lastfm-moreoptions-controls { text-align:center; margin-top:6px; }\n"; 
}
/**
 * Adds a button to the page to toggle the Last FM form.
 */
function addLastFmButton() {
 var buttonId = "lastfm-button";
 var container = document.getElementById("masthead-user-bar-container");
 var lastFmImgCode = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/gD+AP7rGNSCAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAACVElEQVQ4y6WRXUiTURjHDxVFlkxsqZub4twMm5mxydbWjBXZB2QRrSCJuuwygi68E6K7oJsI8qIo0vmx6d50i80MLaTYtGRuM2XMbY7NyhnWdH6s/p33nTPxTjvw45zn+b3/95zDIb/dLrJ8px7L56s2B82wWZKs1yN5rnJr0Cz5VVuB/4HMnihHhjhlRp8mvq6fcd/1adY7Mq0rQ5QS0EgxqiqF55Ieo2dV8KlLEdLKOBemM1t7rtbCYzjJrdlejDoSpIWvugRfGu9iZT6BzPjpH8fI9Tp4qRu5cByJ0OSam4+E4aa9gEoCMnakCMPX6jgx5bChv6YKg4YzmAv4sRifQZ9ShhDTgYVvX2E/dRTvL5/GQjQC/70GsFniPFiIiWdN+JNKoU8txyd5IVy0N3jjCvdTV2MDJhkTVpJJDN6+hV5NJRxlBfhYLoRbLgIZkOYhaGWw+GMWdkkehqkcovTKBEjEoog5P6BHr8LsmHftCkGLCQOqCjhlBSBvivZhvOUFJywHRHhXzOewiXPhfZo+GaOrBiPKxWutAs77jdy3vieP8JZmiUOQg/6b9VzT+/I5WkuE6NYoMdb0GB3KQ/ToC5geHoJFo0BLPg9tOjVSS0uYaDfCRrPEvj8bnfy9+PzwAbdbZsS9HpikYjgMFzEX/PcC3AtNhWHVH4OVnw3Sk5OFV5R23m4YRflgajRolYhhpHUnLwtmSjNdmxWH0UVdl1bF1azrpjnSuWcXMpgpHavzxr5p1W30hCkWo23nji3BZknEZiNmoQDN27dtCjbDZv8CFCxvhvx1W58AAAAASUVORK5CYII%3D";
 var htmlCode = "<div style=\"margin-left: 6px;\" id=\"masthead-user-bar\">" +
 "   <div id=\"masthead-user\">" +
 " <span  name=\"lastfm-expander\" class=\"yt-uix-expander yt-uix-expander-collapsed\" id=\"masthead-user-expander\">" +
 "     <span id=\"lastfm-button\">" +
 "     <span tabindex=\"1\" class=\"yt-uix-expander-head yt-rounded\" id=\"masthead-user-wrapper\">" +
 "  <button role=\"button\" class=\"yt-uix-button yt-uix-button-text yt-uix-button-toggle\" id=\"masthead-user-button\" type=\"button\">" +
 "      <span class=\"yt-uix-button-content\">" +
 "   <span id=\"masthead-user-image\">" +
 "       <span class=\"clip\">" +
 "    <span class=\"clip-center\">" +
 "        <img alt=\"Last.FM\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/gD+AP7rGNSCAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAACVElEQVQ4y6WRXUiTURjHDxVFlkxsqZub4twMm5mxydbWjBXZB2QRrSCJuuwygi68E6K7oJsI8qIo0vmx6d50i80MLaTYtGRuM2XMbY7NyhnWdH6s/p33nTPxTjvw45zn+b3/95zDIb/dLrJ8px7L56s2B82wWZKs1yN5rnJr0Cz5VVuB/4HMnihHhjhlRp8mvq6fcd/1adY7Mq0rQ5QS0EgxqiqF55Ieo2dV8KlLEdLKOBemM1t7rtbCYzjJrdlejDoSpIWvugRfGu9iZT6BzPjpH8fI9Tp4qRu5cByJ0OSam4+E4aa9gEoCMnakCMPX6jgx5bChv6YKg4YzmAv4sRifQZ9ShhDTgYVvX2E/dRTvL5/GQjQC/70GsFniPFiIiWdN+JNKoU8txyd5IVy0N3jjCvdTV2MDJhkTVpJJDN6+hV5NJRxlBfhYLoRbLgIZkOYhaGWw+GMWdkkehqkcovTKBEjEoog5P6BHr8LsmHftCkGLCQOqCjhlBSBvivZhvOUFJywHRHhXzOewiXPhfZo+GaOrBiPKxWutAs77jdy3vieP8JZmiUOQg/6b9VzT+/I5WkuE6NYoMdb0GB3KQ/ToC5geHoJFo0BLPg9tOjVSS0uYaDfCRrPEvj8bnfy9+PzwAbdbZsS9HpikYjgMFzEX/PcC3AtNhWHVH4OVnw3Sk5OFV5R23m4YRflgajRolYhhpHUnLwtmSjNdmxWH0UVdl1bF1azrpjnSuWcXMpgpHavzxr5p1W30hCkWo23nji3BZknEZiNmoQDN27dtCjbDZv8CFCxvhvx1W58AAAAASUVORK5CYII%3D\">" +
 "        <span class=\"vertical-center\">" +
 "        </span>" +
 "    </span>" +
 "       </span>" +
 "   </span>" +
 "   <span class=\"yt-uix-expander-arrow\">" +
 "   </span>" +
 "      </span>" +
 "  </button>" +
 "     </span>" +
 "  </span>" +
 " </span>" +
 " </div>" +
 "</div>";
 
 container.innerHTML += htmlCode;
 var button = document.getElementById(buttonId);
 button.addEventListener("click", toggleLastFmForm, false);
 
 if(scrobbleAutoCollapse !== true && scrobbleAutoCollapse !== "true") {
  toggleLastFmForm();
  var buttonCont = document.getElementById("lastfm-button").parentNode;
  var newClass = buttonCont.getAttribute("class") + "yt-uix-expander-collapsed";
  buttonCont.setAttribute("class", newClass);
 }
}
/**
 * Adds a division with the Last FM menu. 
 */
function addLastFmOptions() {
 var swapImgCode = "data:image/png;base64,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";
 var scrobbleSmurfImgCode = "data:image/png;base64,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%3D";
 var htmlCode = "<div id=\"masthead-lastfm\" style=\"display: none;\">\n" +
 " <div id=\"lastfm-container\">\n" +
 "  <ul id=\"lastfm-options\">\n" +
 "  <li id=\"lastfm-options-resetlogin\">\n" +
 "   <h3>Authenticate</h3>\n" +
 "   <p>Logged in as: <br/><span id=\"lastfm-username\"></span></p>\n" +
 "   <button class=\"yt-uix-button yt-uix-tooltip\" id=\"lastfm-reset\" title=\"Log out from Last FM\"><span class=\"yt-uix-button-content\">Reset</span></button>\n" +
 "  </li>\n" +
 "  <li id=\"lastfm-options-login\">" +
 "   <h3>Authenticate</h3>\n" +
 "   <p>To log in this page <br/>will be closed.</p>" +
 "   <button class=\"yt-uix-button yt-uix-tooltip\" id=\"lastfm-login\" title=\"Log in to Last FM\"><span class=\"yt-uix-button-content\">Authenticate</span></button>" +
 "  </li>\n" +
 "  <li>\n" +
 "   <h3>Miscellaneous</h3>\n" +
 "   <button class=\"yt-uix-button yt-uix-tooltip\" id=\"lastfm-moreoptions\" title=\"More options menu\"><span class=\"yt-uix-button-content\">More options</span></button><br/>\n" +
 "   <button class=\"yt-uix-button yt-uix-tooltip\" id=\"lastfm-man-scrobble\" title=\"Scrobble now\"><span class=\"yt-uix-button-content\">Scrobble manual</span></button>\n" +
 "  </li>\n" +
 "  <li>\n" +
 "   <h3>Scrobbling</h3>\n" +
 "   <table>\n" +
 "    <tbody>\n" +
 "    <tr><td><p>Artist:</p></td><td><input type=\"text\" id=\"lastfm-artist\"></td><td rowspan=\"2\">" +
 "     <img src=\"" + swapImgCode + "\" id=\"lastfm-swap-songinfo\" width=\"20px\" height=\"41px\"></td></tr>\n" +
 "    <tr><td><p>Title:</p></td><td><input type=\"text\" id=\"lastfm-title\"></td></tr>\n" +
 "    </tbody>\n" +
 "   </table>\n" +
 "  </li>\n" +
 "  <li style=\"max-width: 228px; border-right: none;\">\n" +
 "   <h3>Status</h3>\n" +
 "   <div id=\"scrobble-counter\">\n" +
 "    <p><span id=\"scrobble-in\">Scrobble in:</span> <span id=\"scrobble-time\"></span></p>\n" +
 "    <button class=\"yt-uix-button yt-uix-tooltip\" id=\"lastfm-noscrobble\" title=\"Stops the automatic scrobble timer\"><span class=\"yt-uix-button-content\">Don't scrobble</span></button>\n" +
 "   </div>\n" +
 "   <div id=\"scrobble-message\" style=\"display: none;\">\n" +
 "    <p id=\"scrobble-msg\"></p>\n" + 
 "   </div>\n" +
 "  </li>\n" +
 "  <li style=\"float: right; border-right: none;\">" +
 "   <div id=\"scrobblesmurf-logo\">\n" +
 "    <img src=\"" + scrobbleSmurfImgCode + "\"/>\n" +
 "   </div>\n" +
 "  </li>\n" +
 "  </ul>\n" +
 "  <div style=\"clear: both;\"></div>\n" +
 " </div>\n" +
 "</div>\n";
 var container = document.getElementById("masthead-container");
 container.innerHTML += htmlCode;
}
/**
 * Toggles the Last FM form added by this plug in. 
 * The stated is based on the Last FM button at the right top.
 */
function toggleLastFmForm() {
 var container = document.getElementById("masthead-lastfm");
 var buttonCont = document.getElementById("lastfm-button").parentNode;
 if(countOccurencesInString(buttonCont.getAttribute("class"), "yt-uix-expander-collapsed") >= 1) {
  container.style.display = "block";
 } else { 
  container.style.display = "none";
 }
}
//--Last FM form button listeners and actions.
/**
 * Add event listeners to all the menubuttons added by this plug-in.
 */
function activateLastFmButtons() {
 authenticateButton();
 resetAuthenicateButton();
 dontScrobbleButton();
 moreOptionsButton();
 manScrobbleButton();
 swapSongInfoButton();
}
/**
 * Add the event listener to the 'authenticate'-button.
 */
function authenticateButton() {
 var authButton = document.getElementById("lastfm-login");
 authButton.addEventListener("click", authenticate, false);
}
/**
 * Redirects the user to Last FM to authenticate. When they allow they will 
 * be directed back and an authentication token will be added to the URL.
 */
function authenticate() {
 var tokenRegex = /(\?|&)token=[^&\?]*/gi;
 var currentURL = document.URL.replace(tokenRegex, "");
 if(!stringContainsChar(currentURL, "?")) {
  currentURL = currentURL.replace("&", "?");
 }
 var redirectURL = lastFmAuthenticationUrl + "?api_key=" + apiKey +"&cb=" + currentURL;
 window.location.href = redirectURL;
}
/**
 * Add the event listener to the 'reset login'-button.
 */
function resetAuthenicateButton() {
 var resetButton = document.getElementById("lastfm-reset");
 resetButton.addEventListener("click", resetAuth, false);
}
/**
 * Resets the authentication. A user would have to authenticate again to scrobble.
 */
function resetAuth() {
 localStorage.removeItem("lastfmUsername");
 localStorage.removeItem("lastfmSessionkey");
 showLoginHideReset();
}
/**
 * Adds the event listener to the 'do not scrobble'-button.
 */
function dontScrobbleButton() {
 var dontScrobbleButton = document.getElementById("lastfm-noscrobble");
 dontScrobbleButton.addEventListener("click", dontScrobble, false);
}
/**
 * Disables scrobbling for this time.
 */
function dontScrobble() {
 noScrobble = true;
 
 var dontScrobbleButton = document.getElementById("lastfm-noscrobble");
 dontScrobbleButton.className += " yt-uix-button-toggled";
}
/**
 * Adds the event listener to the 'options'-button.
 */ 
function moreOptionsButton()
{
 var moreOptionsButton = document.getElementById("lastfm-moreoptions");
 moreOptionsButton.addEventListener("click", function(){ moreOptions(false); }, false);
}
/**
 * Shows or hides a pop-up containing some less common options for this plug-in.
 */
function moreOptions(hide)
{
 var back = document.getElementById("lastfm-moreoptions-back");
 var pop = document.getElementById("lastfm-moreoptions-pop");
 
 if(hide) {
  back.style.visibility = "hidden";
  pop.style.visibility = "hidden";
 } else {
  if(scrobbleAutoCollapse === true || scrobbleAutoCollapse === "true") {
   setRadioButtonChecked("lastfm-moreoptions-collapse", "collapse");
  } else {
   setRadioButtonChecked("lastfm-moreoptions-collapse", "expand");
  }
  document.getElementById("lastfm-moreoptions-filter").value = scrobbleFilter;
  if(scrobbleEnabled === true || scrobbleEnabled === "true") {
   setRadioButtonChecked("lastfm-moreoptions-scrobble", "yes");
  } else {
   setRadioButtonChecked("lastfm-moreoptions-scrobble", "no");
  }
 
  pop.style.visibility = "visible";
  back.style.visibility = "visible";
 }
}
/**
 * Adds the event listener to the 'manual scrobble'-button.
 */ 
function manScrobbleButton()
{
 var manScrobbButton = document.getElementById("lastfm-man-scrobble");
 manScrobbButton.addEventListener("click", scrobbleManual, false);
}
/**
 * Disables scrobbling for this time.
 */
function scrobbleManual() {
 noScrobble = true;
 scrobbleSong();
 
 var manScrobbButton = document.getElementById("lastfm-man-scrobble");
 manScrobbButton.removeEventListener('click', scrobbleManual, false);
 manScrobbButton.className += " yt-uix-button-toggled";
}
/**
 * Adds the event listener to the two arrows, the 'swap song info'-button.
 */
function swapSongInfoButton()
{
 var swapSongButton = document.getElementById("lastfm-swap-songinfo");
 swapSongButton.addEventListener("click", swapSongInfo, false);
}
/**
 * Swaps the artist field's value with the title field's value.
 */
function swapSongInfo()
{
 var artistInput = document.getElementById("lastfm-artist");
 var titleInput = document.getElementById("lastfm-title");
 
 var oldArtist = artistInput.value;
 var oldTitle = titleInput.value;
 
 artistInput.value = oldTitle;
 titleInput.value = oldArtist;
}
//--Functions to for song information.
/**
 * Fills the 'song'-form with the passed song.
 */
function fillSongInformation(song) {
 var artistInput = document.getElementById("lastfm-artist");
 var titleInput = document.getElementById("lastfm-title");
 
 if(song.artist != null) {
  artistInput.value = song.artist;
 }
 if(song.title != null) {
  titleInput.value = song.title;
 }
}
/**
 * Gets song information from the currently played YouTube video using the iTunes metadata.
 */
function getSongInformation() {
 var song = new Object();
 song.artist = tryGetArtistMeta();
 song.title = tryGetTitleMeta();
 if(song.artist && song.title) {
  iTunesArtistAndTitleFound = true;
 }
 return song; 
}
/**
 * Gets song artist from the metadata in the video description.
 */
function tryGetArtistMeta() {
 var xPath = "//ul[@id='watch-description-extra-info']/li[@class='full-link']/a/span[@class='metadata-info']/span";
 try { 
  var artistNodes = document.evaluate(xPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
  var artist = artistNodes.singleNodeValue.firstChild.nodeValue;
 } catch (e) {
 }
 return artist;
}
/**
 * Gets song title from the metadata in the video description.
 */
function tryGetTitleMeta() {
 var xPath, title;
 if(cosmicPanda) {
  xPath = "//ul[@id='watch-description-extra-info']/li[2]/span[@class='metadata-info']";
 } else {
  xPath = "//ul[@id='watch-description-extra-info']/li[3]/span[@class='metadata-info']";
 }
 try {
  var songNodes = document.evaluate(xPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
  var rawTitle = songNodes.singleNodeValue.firstChild.nodeValue; //rawSong still contains 'buy on' text.
  rawTitle = removeBreaks(rawTitle);
  title = stringBetweenChars(rawTitle, "\"");
  if(typeof(title) === "undefined") {
   title = stringBetweenChars(rawTitle, "'");
  }
 } catch (e) {
 }
 return title;
}
/**
 * Tries to strip a song's information from the passed video title. 
 * First looks for quoted text which will be used as song title. 
 * The rest of the title will then be used as artist. 
 * If it fails it split the title between a dash and uses the first part as artist. 
 * The second part will be used as title. 
 */
function tryStripSongFromTitle(title) {
 var song = new Object();
 if(countOccurencesInString(title, "\"") >= 2) {
  song = getSongFromQuotedTitle(title, "\"");
 } else if(countOccurencesInString(title, "'") >= 2) {
  song = getSongFromQuotedTitle(title, "'");
 } else if(stringContainsChar(title, "-")) {
  var split = title.split("-");
  song.artist = trim(split[0]);
  song.title = trim(split[1]);
 }
 return song;
}
/**
 * Gets a song from a video title that contains quotes.
 */
function getSongFromQuotedTitle(vidTitle, quoteString) {
 var song = new Object();
 song.title = stringBetweenChars(vidTitle, quoteString);
 var regex = new RegExp(quoteString + song.title + quoteString);
 song.artist = vidTitle.replace(regex, "");
 return song;
}
//--JavaScript common utilization functions.
/**
 * Removes breaks from a text.
 */
function removeBreaks(text) {
 return text.replace(/(\n|\r)/gm, "");
}
/**
 * Checks whether a text contains a character.
 */
function stringContainsChar(text, charac) {
 for(var i = 0; i < text.length; i++) {
  if(text[i] == charac) {
   return true;
  }
 }
 return false;
}
/**
 * Counts the occurences of a certain object in a text.
 */
function countOccurencesInString(text, toMatch) {
 var regex = new RegExp(toMatch, "g");
 var matches = text.match(regex);
 if(matches == null) {
  return 0;
 }
 return matches.length;
}
/**
 * Finds a text between two characters.
 */
function stringBetweenChars(text, charac) {
 var part, results = [];
 var regex = new RegExp(charac + "([^" + charac +"]+)", "g");
 while(part = regex.exec(text)) {
  results.push(part[1]);
 }
 results = results.splice(0, 1);
 if(typeof(results) === "string") {
  return results;
 } else {
  return results[0];
 }
}
/**
 * Trims a text from spaces.
 */
function trim(text) {
 return text.replace(/^\s*/, "").replace(/\s*$/, "");
}
/**
 * Gets the selected value from a radio button group.
 */
function getSelectedRadioButton(name) {
 var radioButtons = document.getElementsByName(name);
 for(x in radioButtons) {
  if(radioButtons[x].checked) {
   return radioButtons[x].value;
  }
 }
 return null;
}
/**
 * Sets all values from a radio button group to unchecked except the passed value's radio button.
 */
function setRadioButtonChecked(name, value) {
 var radioButtons = document.getElementsByName(name);
 for(x in radioButtons) {
  if(radioButtons[x].value == value) {
   radioButtons[x].checked = true;
  } else {
   radioButtons[x].checked = false;
  }
 }
}
/**
 * Sets a select input to a default value.
 */
function setDefaultSelectValue(name, value) {
 var selectInput = document.getElementsByName(name)[0];
 var options = selectInput.getElementsByTagName("option");
 for(var i = 0; i < options.length; i++) {
  if(options[i].value == value) {
   options[i].setAttribute("selected", "");
  } else {
   options[i].removeAttribute("selected");
  }
 }
 
 var parent = selectInput.parentNode;
 parent.removeChild(selectInput);
 parent.appendChild(selectInput);
}

initialize();

0 comments:

Post a Comment