diff -c -r -N minion.orig//chrome/content/about.js minion.patched//chrome/content/about.js
*** minion.orig//chrome/content/about.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/about.js	2012-03-30 23:00:04.613085061 +0200
***************
*** 0 ****
--- 1,132 ----
+ Components.utils.import("chrome://minion/content/mpmUtils.js");
+ 
+ function init() {
+     var rdfs = Components.classes['@mozilla.org/rdf/rdf-service;1'].
+                           getService(Components.interfaces.nsIRDFService);
+     var extension = rdfs.GetResource('urn:mozilla:item:Music_Player_Minion@code.google.com');
+     var gExtensionDB = Components.classes['@mozilla.org/extensions/manager;1'].
+                        getService(Components.interfaces.nsIExtensionManager).
+                        QueryInterface(Components.interfaces.nsIExtensionManager).
+                        datasource;
+ 
+     var extensionsStrings = document.getElementById('extensionsStrings');
+ 
+     // Name
+     var nameArc = rdfs.GetResource(EM_NS('name'));
+     var name = gExtensionDB.GetTarget(extension, nameArc, true);
+     name = name.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+ 
+     // Version
+     var versionArc = rdfs.GetResource(EM_NS('version'));
+     var version = gExtensionDB.GetTarget(extension, versionArc, true);
+     version = version.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+ 
+     // Description
+     var descriptionArc = rdfs.GetResource(EM_NS('description'));
+     var description = gExtensionDB.GetTarget(extension, descriptionArc, true);
+     if (description)
+       description = description.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+ 
+     // Home Page URL
+     var homepageArc = rdfs.GetResource(EM_NS('homepageURL'));
+     var homepage = gExtensionDB.GetTarget(extension, homepageArc, true);
+     if (homepage) {
+         homepage = homepage.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+         // only allow http(s) homepages
+         var scheme = '';
+         var uri = null;
+         try {
+             uri = makeURI(homepage);
+             scheme = uri.scheme;
+         }
+         catch (ex) {}
+ 
+         if (uri && (scheme == 'http' || scheme == 'https'))
+             homepage = uri.spec;
+         else
+             homepage = null;
+     }
+ 
+     // Creator
+     var creatorArc = rdfs.GetResource(EM_NS('creator'));
+     var creator = gExtensionDB.GetTarget(extension, creatorArc, true);
+     if (creator)
+         creator = creator.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+ 
+     document.title = extensionsStrings.getFormattedString('aboutWindowTitle', [name]);
+     var extensionName = document.getElementById('extensionName');
+     extensionName.setAttribute('value', name);
+     var extensionVersion = document.getElementById('extensionVersion');
+     extensionVersion.setAttribute('value', version);
+ 
+     var extensionDescription = document.getElementById('extensionDescription');
+     extensionDescription.appendChild(document.createTextNode(description));
+ 
+     var extensionCreator = document.getElementById('extensionCreator');
+     extensionCreator.setAttribute('value', creator);
+ 
+     var extensionHomepage = document.getElementById('extensionHomepage');
+     if (homepage) {
+         extensionHomepage.setAttribute('homepageURL', homepage);
+         extensionHomepage.setAttribute('tooltiptext', homepage);
+         extensionHomepage.blur();
+     }
+     else
+         extensionHomepage.hidden = true;
+ 
+     // Translators
+     var translatorArc = rdfs.GetResource(EM_NS('translator'));
+     var targets = gExtensionDB.GetTargets(extension, translatorArc, true);
+     if (!targets.hasMoreElements()) {
+         document.getElementById('extensionTranslators').hidden = true;
+     } else {
+         var i = 0;
+         var rows = document.getElementById('translatorsRows');
+         while (targets.hasMoreElements()) {
+             var literalValue = targets.getNext().
+                                QueryInterface(Components.interfaces.nsIRDFLiteral).
+                                Value;
+ 
+             if (i / 2 == Math.floor(i / 2)) {
+                 var row = document.createElement('row');
+                 rows.appendChild(row);
+             }
+ 
+             var label = document.createElement('label');
+             label.setAttribute('value', literalValue);
+             label.setAttribute('class', 'contributor');
+             row.appendChild(label);
+             i++;
+         }
+     }
+ 
+     // Contributors
+     var node = document.getElementById('contributorsBox');
+     var arc = rdfs.GetResource(EM_NS('contributor'));
+     var targets = gExtensionDB.GetTargets(extension, arc, true);
+     if (!targets.hasMoreElements())
+         document.getElementById('extensionContributors').hidden = true;
+     else {
+         while (targets.hasMoreElements()) {
+             var literalValue = targets.getNext().
+                                QueryInterface(Components.interfaces.nsIRDFLiteral).
+                                Value;
+             var label = document.createElement('label');
+             label.setAttribute('value', literalValue);
+             label.setAttribute('class', 'contributor');
+             node.appendChild(label);
+         }
+     }
+ 
+     var acceptButton = document.documentElement.getButton('accept');
+     acceptButton.label = extensionsStrings.getString('aboutWindowCloseButton');
+ }
+ 
+ function EM_NS(aProperty) {
+     return 'http://www.mozilla.org/2004/em-rdf#' + aProperty;
+ }
+ 
+ function loadHomepage(aEvent) {
+     window.close();
+     window.opener.openURL(aEvent.target.getAttribute('homepageURL'));
+ }
diff -c -r -N minion.orig//chrome/content/browser_overlay.js minion.patched//chrome/content/browser_overlay.js
*** minion.orig//chrome/content/browser_overlay.js	2012-03-30 23:07:40.153062918 +0200
--- minion.patched//chrome/content/browser_overlay.js	2012-03-30 22:55:49.349097470 +0200
***************
*** 1,4 ****
! Components.utils.import("resource://minion/mpmUtils.js");
  nsMPM.debug("Starting Music player Minion...");
  
  nsMPM.debug("Checking for upgrades...");
--- 1,4 ----
! Components.utils.import("chrome://minion/content/mpmUtils.js");
  nsMPM.debug("Starting Music player Minion...");
  
  nsMPM.debug("Checking for upgrades...");
diff -c -r -N minion.orig//chrome/content/browser_overlay.xul minion.patched//chrome/content/browser_overlay.xul
*** minion.orig//chrome/content/browser_overlay.xul	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/content/browser_overlay.xul	2012-03-30 22:43:47.301132569 +0200
***************
*** 6,11 ****
--- 6,13 ----
  <!DOCTYPE overlay SYSTEM "chrome://minion/locale/minion.dtd">
  
  <overlay id="minion-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+     <script src="resource://minion/mpmCommon.js"/>
+     <script src="resource://minion/mpmUtils.js"/>
      <script src="chrome://minion/content/browser_overlay.js"/>
      <script src="chrome://minion/content/menus.js"/>
      
diff -c -r -N minion.orig//chrome/content/collectionBindings.xml minion.patched//chrome/content/collectionBindings.xml
*** minion.orig//chrome/content/collectionBindings.xml	2012-03-30 23:07:40.153062918 +0200
--- minion.patched//chrome/content/collectionBindings.xml	2012-03-30 22:59:39.665086275 +0200
***************
*** 350,357 ****
          </content>
          <implementation>
              <constructor>
!                 Components.utils.import("resource://minion/mpmUtils.js");
!                 Components.utils.import("resource://minion/trees.js");
                  this.treeNode = document.getAnonymousNodes(this)[0]
                  this.box = this.treeNode.boxObject;
                  this.box.QueryInterface(Components.interfaces.nsITreeBoxObject)
--- 350,357 ----
          </content>
          <implementation>
              <constructor>
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
!                 Components.utils.import("chrome://minion/content/trees.js");
                  this.treeNode = document.getAnonymousNodes(this)[0]
                  this.box = this.treeNode.boxObject;
                  this.box.QueryInterface(Components.interfaces.nsITreeBoxObject)
***************
*** 484,491 ****
              <field name="typeMain">document.getAnonymousElementByAttribute(this, 'id', 'tagsMainType')</field>
              <field name="typeSub">document.getAnonymousElementByAttribute(this, 'id', 'tagsSubType')</field>
              <constructor>
!                 Components.utils.import("resource://minion/mpmUtils.js");
!                 Components.utils.import("resource://minion/trees.js");
                  var me = this
                  this.observerServer = {
                      observe: function(subject,topic,data){
--- 484,491 ----
              <field name="typeMain">document.getAnonymousElementByAttribute(this, 'id', 'tagsMainType')</field>
              <field name="typeSub">document.getAnonymousElementByAttribute(this, 'id', 'tagsSubType')</field>
              <constructor>
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
!                 Components.utils.import("chrome://minion/content/trees.js");
                  var me = this
                  this.observerServer = {
                      observe: function(subject,topic,data){
***************
*** 723,730 ****
              <field name="tags">document.getAnonymousElementByAttribute(this, 'id', 'tags')</field>
              <constructor>
                  <![CDATA[
!                 Components.utils.import("resource://minion/mpmUtils.js");
!                 Components.utils.import("resource://minion/trees.js");
  				var hideEC = nsMPM.prefs.get("hide_extra_clearplaylist", true)
  				document.getAnonymousElementByAttribute(this, 'id', 'browse_Clear_btn').setAttribute('collapsed', hideEC)
                  var me = this
--- 723,730 ----
              <field name="tags">document.getAnonymousElementByAttribute(this, 'id', 'tags')</field>
              <constructor>
                  <![CDATA[
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
!                 Components.utils.import("chrome://minion/content/trees.js");
  				var hideEC = nsMPM.prefs.get("hide_extra_clearplaylist", true)
  				document.getAnonymousElementByAttribute(this, 'id', 'browse_Clear_btn').setAttribute('collapsed', hideEC)
                  var me = this
diff -c -r -N minion.orig//chrome/content/fileActions.xul minion.patched//chrome/content/fileActions.xul
*** minion.orig//chrome/content/fileActions.xul	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/content/fileActions.xul	2012-03-30 22:59:50.485085749 +0200
***************
*** 15,21 ****
      ondialogcancel="return doCancel();">
      <script>
      <![CDATA[
!         Components.utils.import("resource://minion/mpmUtils.js");
          function load () {
              var fa = document.getElementById("file_action")
              var d = parseInt(nsMPM.prefs.get("default_file_action", 0))
--- 15,21 ----
      ondialogcancel="return doCancel();">
      <script>
      <![CDATA[
!         Components.utils.import("chrome://minion/content/mpmUtils.js");
          function load () {
              var fa = document.getElementById("file_action")
              var d = parseInt(nsMPM.prefs.get("default_file_action", 0))
diff -c -r -N minion.orig//chrome/content/io.js minion.patched//chrome/content/io.js
*** minion.orig//chrome/content/io.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/io.js	2012-03-30 22:47:24.253122023 +0200
***************
*** 0 ****
--- 1,319 ----
+ /////////////////////////////////////////////////
+ /////////////////////////////////////////////////
+ //
+ // Basic JavaScript File and Directory IO module
+ // By: MonkeeSage, v0.1
+ //
+ /////////////////////////////////////////////////
+ /////////////////////////////////////////////////
+ let EXPORTED_SYMBOLS = ["FileIO", "DirIO"]
+ /////////////////////////////////////////////////
+ // Basic file IO object based on Mozilla source
+ // code post at forums.mozillazine.org
+ /////////////////////////////////////////////////
+ 
+ // Example use:
+ // var fileIn = FileIO.open('/test.txt');
+ // if (fileIn.exists()) {
+ // 	var fileOut = FileIO.open('/copy of test.txt');
+ // 	var str = FileIO.read(fileIn);
+ // 	var rv = FileIO.write(fileOut, str);
+ // 	alert('File write: ' + rv);
+ // 	rv = FileIO.write(fileOut, str, 'a');
+ // 	alert('File append: ' + rv);
+ // 	rv = FileIO.unlink(fileOut);
+ // 	alert('File unlink: ' + rv);
+ // }
+ 
+ var FileIO = {
+ 
+     localfileCID  : '@mozilla.org/file/local;1',
+     localfileIID  : Components.interfaces.nsILocalFile,
+ 
+     finstreamCID  : '@mozilla.org/network/file-input-stream;1',
+     finstreamIID  : Components.interfaces.nsIFileInputStream,
+ 
+     foutstreamCID : '@mozilla.org/network/file-output-stream;1',
+     foutstreamIID : Components.interfaces.nsIFileOutputStream,
+ 
+     sinstreamCID  : '@mozilla.org/scriptableinputstream;1',
+     sinstreamIID  : Components.interfaces.nsIScriptableInputStream,
+ 
+     suniconvCID   : '@mozilla.org/intl/scriptableunicodeconverter',
+     suniconvIID   : Components.interfaces.nsIScriptableUnicodeConverter,
+ 
+     open   : function(path) {
+         try {
+             var file = Components.classes[this.localfileCID]
+                             .createInstance(this.localfileIID);
+             file.initWithPath(path);
+             return file;
+         }
+         catch(e) {
+             return false;
+         }
+     },
+ 
+     read   : function(file, charset) {
+         try {
+             var data     = new String();
+             var fiStream = Components.classes[this.finstreamCID]
+                                 .createInstance(this.finstreamIID);
+             var siStream = Components.classes[this.sinstreamCID]
+                                 .createInstance(this.sinstreamIID);
+             fiStream.init(file, 1, 0, false);
+             siStream.init(fiStream);
+             data += siStream.read(-1);
+             siStream.close();
+             fiStream.close();
+             if (charset) {
+                 data = this.toUnicode(charset, data);
+             }
+             return data;
+         }
+         catch(e) {
+             return false;
+         }
+     },
+ 
+     write  : function(file, data, mode, charset) {
+         try {
+             var foStream = Components.classes[this.foutstreamCID]
+                                 .createInstance(this.foutstreamIID);
+             if (charset) {
+                 data = this.fromUnicode(charset, data);
+             }
+             var flags = 0x02 | 0x08 | 0x20; // wronly | create | truncate
+             if (mode == 'a') {
+                 flags = 0x02 | 0x10; // wronly | append
+             }
+             foStream.init(file, flags, 0664, 0);
+             foStream.write(data, data.length);
+             // foStream.flush();
+             foStream.close();
+             return true;
+         }
+         catch(e) {
+             return false;
+         }
+     },
+ 
+     create : function(file) {
+         try {
+             file.create(0x00, 0664);
+             return true;
+         }
+         catch(e) {
+             return e.description;
+         }
+     },
+ 
+     unlink : function(file) {
+         try {
+             file.remove(false);
+             return true;
+         }
+         catch(e) {
+             return false;
+         }
+     },
+ 
+     path   : function(file) {
+         try {
+             return 'file:///' + file.path.replace(/\\/g, '\/')
+                         .replace(/^\s*\/?/, '').replace(/\ /g, '%20');
+         }
+         catch(e) {
+             return false;
+         }
+     },
+ 
+     toUnicode   : function(charset, data) {
+         try{
+             var uniConv = Components.classes[this.suniconvCID]
+                                 .createInstance(this.suniconvIID);
+             uniConv.charset = charset;
+             data = uniConv.ConvertToUnicode(data);
+         }
+         catch(e) {
+             // foobar!
+         }
+         return data;
+     },
+ 
+     fromUnicode : function(charset, data) {
+         try {
+             var uniConv = Components.classes[this.suniconvCID]
+                                 .createInstance(this.suniconvIID);
+             uniConv.charset = charset;
+             data = uniConv.ConvertFromUnicode(data);
+             // data += uniConv.Finish();
+         }
+         catch(e) {
+             // foobar!
+         }
+         return data;
+     }
+ 
+ }
+ 
+ 
+ /////////////////////////////////////////////////
+ // Basic Directory IO object based on JSLib
+ // source code found at jslib.mozdev.org
+ /////////////////////////////////////////////////
+ 
+ // Example use:
+ // var dir = DirIO.open('/test');
+ // if (dir.exists()) {
+ // 	alert(DirIO.path(dir));
+ // 	var arr = DirIO.read(dir, true), i;
+ // 	if (arr) {
+ // 		for (i = 0; i < arr.length; ++i) {
+ // 			alert(arr[i].path);
+ // 		}
+ // 	}
+ // }
+ // else {
+ // 	var rv = DirIO.create(dir);
+ // 	alert('Directory create: ' + rv);
+ // }
+ 
+ // ---------------------------------------------
+ // ----------------- Nota Bene -----------------
+ // ---------------------------------------------
+ // Some possible types for get are:
+ // 	'ProfD'				= profile
+ // 	'DefProfRt'			= user (e.g., /root/.mozilla)
+ // 	'UChrm'				= %profile%/chrome
+ // 	'DefRt'				= installation
+ // 	'PrfDef'				= %installation%/defaults/pref
+ // 	'ProfDefNoLoc'		= %installation%/defaults/profile
+ // 	'APlugns'			= %installation%/plugins
+ // 	'AChrom'				= %installation%/chrome
+ // 	'ComsD'				= %installation%/components
+ // 	'CurProcD'			= installation (usually)
+ // 	'Home'				= OS root (e.g., /root)
+ // 	'TmpD'				= OS tmp (e.g., /tmp)
+ 
+ var DirIO = {
+ 
+     sep        : '/',
+ 
+     dirservCID : '@mozilla.org/file/directory_service;1',
+ 
+     propsIID   : Components.interfaces.nsIProperties,
+ 
+     fileIID    : Components.interfaces.nsIFile,
+ 
+     get    : function(type) {
+         try {
+             var dir = Components.classes[this.dirservCID]
+                             .createInstance(this.propsIID)
+                             .get(type, this.fileIID);
+             return dir;
+         }
+         catch(e) {
+             return false;
+         }
+     },
+ 
+     open   : function(path) {
+         return FileIO.open(path);
+     },
+ 
+     create : function(dir) {
+         try {
+             dir.create(0x01, 0640);
+             return true;
+         }
+         catch(e) {
+             return false;
+         }
+     },
+ 
+     read   : function(dir, recursive) {
+         var list = new Array();
+         try {
+             if (dir.isDirectory()) {
+                 if (recursive == null) {
+                     recursive = false;
+                 }
+                 var files = dir.directoryEntries;
+                 list = this._read(files, recursive);
+             }
+         }
+         catch(e) {
+             // foobar!
+         }
+         return list;
+     },
+ 
+     _read  : function(dirEntry, recursive) {
+         var list = new Array();
+         try {
+             while (dirEntry.hasMoreElements()) {
+                 list.push(dirEntry.getNext()
+                                 .QueryInterface(FileIO.localfileIID));
+             }
+             if (recursive) {
+                 var list2 = new Array();
+                 for (var i = 0; i < list.length; ++i) {
+                     if (list[i].isDirectory()) {
+                         files = list[i].directoryEntries;
+                         list2 = this._read(files, recursive);
+                     }
+                 }
+                 for (i = 0; i < list2.length; ++i) {
+                     list.push(list2[i]);
+                 }
+             }
+         }
+         catch(e) {
+            // foobar!
+         }
+         return list;
+     },
+ 
+     unlink : function(dir, recursive) {
+         try {
+             if (recursive == null) {
+                 recursive = false;
+             }
+             dir.remove(recursive);
+             return true;
+         }
+         catch(e) {
+             return false;
+         }
+     },
+ 
+     path   : function (dir) {
+         return FileIO.path(dir);
+     },
+ 
+     split  : function(str, join) {
+         var arr = str.split(/\/|\\/), i;
+         str = new String();
+         for (i = 0; i < arr.length; ++i) {
+             str += arr[i] + ((i != arr.length - 1) ?
+                                     join : '');
+         }
+         return str;
+     },
+ 
+     join   : function(str, split) {
+         var arr = str.split(split), i;
+         str = new String();
+         for (i = 0; i < arr.length; ++i) {
+             str += arr[i] + ((i != arr.length - 1) ?
+                                     this.sep : '');
+         }
+         return str;
+     }
+ 
+ }
+ 
+ /* if (navigator.platform.toLowerCase().indexOf('win') > -1) {
+     DirIO.sep = '\\';
+ } */
diff -c -r -N minion.orig//chrome/content/JSON.js minion.patched//chrome/content/JSON.js
*** minion.orig//chrome/content/JSON.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/JSON.js	2012-03-30 22:47:24.257122024 +0200
***************
*** 0 ****
--- 1,83 ----
+ /* ***** BEGIN LICENSE BLOCK *****
+  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+  *
+  * The contents of this file are subject to the Mozilla Public License Version
+  * 1.1 (the "License"); you may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at
+  * http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an "AS IS" basis,
+  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+  * for the specific language governing rights and limitations under the
+  * License.
+  *
+  * The Original Code is Personas.
+  *
+  * The Initial Developer of the Original Code is Mozilla.
+  * Portions created by the Initial Developer are Copyright (C) 2008
+  * the Initial Developer. All Rights Reserved.
+  *
+  * Contributor(s):
+  *   Myk Melez <myk@mozilla.org>
+  *
+  * Alternatively, the contents of this file may be used under the terms of
+  * either the GNU General Public License Version 2 or later (the "GPL"), or
+  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+  * in which case the provisions of the GPL or the LGPL are applicable instead
+  * of those above. If you wish to allow use of your version of this file only
+  * under the terms of either the GPL or the LGPL, and not to allow others to
+  * use your version of this file under the terms of the MPL, indicate your
+  * decision by deleting the provisions above and replace them with the notice
+  * and other provisions required by the GPL or the LGPL. If you do not delete
+  * the provisions above, a recipient may use your version of this file under
+  * the terms of any one of the MPL, the GPL or the LGPL.
+  *
+  * ***** END LICENSE BLOCK ***** */
+ 
+ /**
+  * This module wraps the incompatible Gecko 1.9.0 (Firefox 3.0) and Gecko 1.9.1
+  * (Firefox 3.5) JSON APIs, presenting the Gecko 1.9.1 API on both versions,
+  * for extensions that support multiple versions of Gecko-based applications.
+  *
+  * Import this module into your extension to parse and stringify JSON in both
+  * Firefox 3.0 and 3.5 (and other Gecko-based applications, like Thunderbird)
+  * without checking the application's version each time.
+  *
+  * Note: don't import this into the global namespace!  If you do, you'll hork
+  * native application code that expects the Gecko 1.9.0 API.  Instead, import it
+  * into your own object like this:
+  *
+  *   let MyExtension = {
+  *     JSON: null,
+  *     ...
+  *   };
+  *   Components.utils.import("chrome://myextension/modules/JSON.js", MyExtension);
+  *   // Now MyExtension.JSON is an object implementing the Gecko 1.9.1 JSON API.
+  *
+  * The Gecko 1.9.1 (Firefox 3.5) JSON API is documented in the article:
+  *   https://developer.mozilla.org/En/Using_JSON_in_Firefox
+  */
+ 
+ let EXPORTED_SYMBOLS = ["JSON"];
+ 
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const Cr = Components.results;
+ const Cu = Components.utils;
+ 
+ let appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
+ 
+ // Iceweasel 3.0 has a bug where it reports its platform version as 1.9 instead
+ // of 1.9.0.n; we work around the bug by checking for 1.9 in addition to 1.9.0.n
+ // and wrapping the JSON API in both cases.
+ if (appInfo.platformVersion.indexOf("1.9.0") == 0 ||
+     appInfo.platformVersion == "1.9") {
+   // Declare JSON with |var| so it'll be defined outside the enclosing
+   // conditional block.
+   var JSON = {
+       JSON: null,
+       parse: function(jsonString) { return this.JSON.fromString(jsonString) },
+       stringify: function(jsObject) { return this.JSON.toString(jsObject) }
+   }
+   Cu.import("resource://gre/modules/JSON.jsm", JSON);
+ }
diff -c -r -N minion.orig//chrome/content/menuEditor.xul minion.patched//chrome/content/menuEditor.xul
*** minion.orig//chrome/content/menuEditor.xul	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/content/menuEditor.xul	2012-03-30 23:00:15.489084533 +0200
***************
*** 15,21 ****
      ondialogcancel="return doCancel();">
      <script>
      <![CDATA[
!         Components.utils.import("resource://minion/mpmUtils.js");
          
  		function addMenuItem (index, sep) {
  			var xul = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
--- 15,21 ----
      ondialogcancel="return doCancel();">
      <script>
      <![CDATA[
!         Components.utils.import("chrome://minion/content/mpmUtils.js");
          
  		function addMenuItem (index, sep) {
  			var xul = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
diff -c -r -N minion.orig//chrome/content/menus.js minion.patched//chrome/content/menus.js
*** minion.orig//chrome/content/menus.js	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/content/menus.js	2012-03-30 22:53:52.825103134 +0200
***************
*** 1,4 ****
! Components.utils.import("resource://minion/mpmUtils.js");
  
  function isValid(self, item, loc) {
      var type = (nsMPM.Nz(item)) ? nsMPM.Nz(item.type, "undefined") : "undefined"
--- 1,4 ----
! Components.utils.import("chrome://minion/content/mpmUtils.js");
  
  function isValid(self, item, loc) {
      var type = (nsMPM.Nz(item)) ? nsMPM.Nz(item.type, "undefined") : "undefined"
diff -c -r -N minion.orig//chrome/content/minion.js minion.patched//chrome/content/minion.js
*** minion.orig//chrome/content/minion.js	2012-03-30 23:07:40.153062918 +0200
--- minion.patched//chrome/content/minion.js	2012-03-30 23:00:28.261083913 +0200
***************
*** 1,5 ****
! Components.utils.import("resource://minion/mpmUtils.js");
! Components.utils.import("resource://minion/trees.js");
  
  var postinittimer = Components.classes["@mozilla.org/timer;1"]
                  .createInstance(Components.interfaces.nsITimer);
--- 1,5 ----
! Components.utils.import("chrome://minion/content/mpmUtils.js");
! Components.utils.import("chrome://minion/content/trees.js");
  
  var postinittimer = Components.classes["@mozilla.org/timer;1"]
                  .createInstance(Components.interfaces.nsITimer);
diff -c -r -N minion.orig//chrome/content/minion.xul minion.patched//chrome/content/minion.xul
*** minion.orig//chrome/content/minion.xul	2012-03-30 23:07:40.153062918 +0200
--- minion.patched//chrome/content/minion.xul	2011-12-31 10:58:22.000000000 +0100
***************
*** 9,15 ****
  
  <window
      id="main"
!     title="&appname; __mpm_version__"
      orient="vertical"
      xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
      xmlns:html="http://www.w3.org/1999/xhtml"
--- 9,15 ----
  
  <window
      id="main"
!     title="&appname; 2.1.2"
      orient="vertical"
      xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
      xmlns:html="http://www.w3.org/1999/xhtml"
diff -c -r -N minion.orig//chrome/content/mpdControls.xml minion.patched//chrome/content/mpdControls.xml
*** minion.orig//chrome/content/mpdControls.xml	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/content/mpdControls.xml	2012-03-30 22:52:20.165107638 +0200
***************
*** 12,18 ****
              <field name="observedAttribute">"value"</field>
              <field name="observedValue"/>
              <constructor>
!                 Components.utils.import("resource://minion/mpmUtils.js");
                  this.child.className = "mpdObserver_"+this.observes
                  this.child.setAttribute(this.observedAttribute, nsMPM.mpd[this.observes])
                  var me = this
--- 12,18 ----
              <field name="observedAttribute">"value"</field>
              <field name="observedValue"/>
              <constructor>
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
                  this.child.className = "mpdObserver_"+this.observes
                  this.child.setAttribute(this.observedAttribute, nsMPM.mpd[this.observes])
                  var me = this
***************
*** 53,59 ****
              <field name="observer"/>
              <field name="observes">"file"</field>
              <constructor>
!                 Components.utils.import("resource://minion/mpmUtils.js");
                  this.child.className = "mpdAlbumCover"
                  var me = this
                  this.observer = {
--- 53,59 ----
              <field name="observer"/>
              <field name="observes">"file"</field>
              <constructor>
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
                  this.child.className = "mpdAlbumCover"
                  var me = this
                  this.observer = {
***************
*** 112,118 ****
                  onget="return nsMPM.mpd.state"
                  onset="if (val=='play' || val=='pause' || val=='stop') nsMPM.mpd.doCmd(val)"/>
              <constructor>
!                 Components.utils.import("resource://minion/mpmUtils.js");
                  var prev = document.getAnonymousNodes(this)[0]
                  var deck = document.getAnonymousNodes(this)[1]
                  var next = document.getAnonymousNodes(this)[2]
--- 112,118 ----
                  onget="return nsMPM.mpd.state"
                  onset="if (val=='play' || val=='pause' || val=='stop') nsMPM.mpd.doCmd(val)"/>
              <constructor>
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
                  var prev = document.getAnonymousNodes(this)[0]
                  var deck = document.getAnonymousNodes(this)[1]
                  var next = document.getAnonymousNodes(this)[2]
***************
*** 235,241 ****
              <field name="outputs_box">document.getAnonymousElementByAttribute(this, 'id', 'outputs_box')</field>
              <constructor>
                  <![CDATA[
!                 Components.utils.import("resource://minion/mpmUtils.js");
                  this.toolbarbutton = document.getAnonymousNodes(this)[0]
                  var me = this
                  me.refreshServers()
--- 235,241 ----
              <field name="outputs_box">document.getAnonymousElementByAttribute(this, 'id', 'outputs_box')</field>
              <constructor>
                  <![CDATA[
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
                  this.toolbarbutton = document.getAnonymousNodes(this)[0]
                  var me = this
                  me.refreshServers()
***************
*** 307,318 ****
                  }
                  var NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                  var len = nsMPM.mpd.servers.length
!                 var class = "mpm_btn_Settings"
                  for (var i=0;i<len;i++) {
                      var item = document.createElementNS(NS, "menuitem")
                      var this_server = "MPD@"+nsMPM.mpd.servers[i][1].split(":",3).slice(0,2).join(":")
                      var active = (nsMPM.mpd.greeting==this_server)
!                     if (active) class += " mpm_server_connected"
                      item.setAttribute("type", "radio")
                      item.setAttribute("name", "servers")
                      item.setAttribute("checked", active)
--- 307,318 ----
                  }
                  var NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                  var len = nsMPM.mpd.servers.length
!                 var settingsClass = "mpm_btn_Settings"
                  for (var i=0;i<len;i++) {
                      var item = document.createElementNS(NS, "menuitem")
                      var this_server = "MPD@"+nsMPM.mpd.servers[i][1].split(":",3).slice(0,2).join(":")
                      var active = (nsMPM.mpd.greeting==this_server)
!                     if (active) settingsClass += " mpm_server_connected"
                      item.setAttribute("type", "radio")
                      item.setAttribute("name", "servers")
                      item.setAttribute("checked", active)
***************
*** 321,327 ****
                      item.onclick = function(){me.serverSelect(this.value)}
                      this.servers_box.appendChild(item)
                  }
!                 this.toolbarbutton.className = class
                  ]]>
                  </body>
              </method>
--- 321,327 ----
                      item.onclick = function(){me.serverSelect(this.value)}
                      this.servers_box.appendChild(item)
                  }
!                 this.toolbarbutton.className = settingsClass; 
                  ]]>
                  </body>
              </method>
***************
*** 372,378 ****
                  onset=""/>
              <constructor>
                  <![CDATA[
!                 Components.utils.import("resource://minion/mpmUtils.js");
                  var lbl1 = this.lbl1 = document.getAnonymousNodes(this)[0]
                  var progress = this.progress = document.getAnonymousNodes(this)[1]
                  var lblSep = document.getAnonymousNodes(this)[2]
--- 372,378 ----
                  onset=""/>
              <constructor>
                  <![CDATA[
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
                  var lbl1 = this.lbl1 = document.getAnonymousNodes(this)[0]
                  var progress = this.progress = document.getAnonymousNodes(this)[1]
                  var lblSep = document.getAnonymousNodes(this)[2]
***************
*** 499,505 ****
                  onget="return nsMPM.mpd.volume"
                  onset="this.setvol(val)"/>
              <constructor>
!                 Components.utils.import("resource://minion/mpmUtils.js");
                  var scale = document.getAnonymousNodes(this)[0];
                  if (scale.orient=="vertical") scale.setAttribute("dir", "reverse")
                  scale.value = nsMPM.mpd.volume
--- 499,505 ----
                  onget="return nsMPM.mpd.volume"
                  onset="this.setvol(val)"/>
              <constructor>
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
                  var scale = document.getAnonymousNodes(this)[0];
                  if (scale.orient=="vertical") scale.setAttribute("dir", "reverse")
                  scale.value = nsMPM.mpd.volume
diff -c -r -N minion.orig//chrome/content/mpd.js minion.patched//chrome/content/mpd.js
*** minion.orig//chrome/content/mpd.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/mpd.js	2012-03-30 22:53:41.141103702 +0200
***************
*** 0 ****
--- 1,1276 ----
+ /**
+  * Music Player Minion Copyright 2008, Chris Seickel
+  *
+  * This program is free software; you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free Software
+  * Foundation; either version 2 of the License, or (at your option) any later
+  * version.
+  *
+  * This program is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+  * details.
+  *
+  * You should have received a copy of the GNU General Public License along with
+  * this program; if not, write to the Free Software Foundation, Inc., 51
+  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ Components.utils.import("chrome://minion/content/mpmUtils.js");
+ 
+ let EXPORTED_SYMBOLS = ["dbQuery", "mpd"]
+ 
+ var lfId = nsMPM.prefs.get("lyricsfly_id","8890a06f973057f4b")
+ 
+ const NOSRV_STATUS = 2152398861
+ const LOSTC_STATUS = 2152398868
+ 
+ var default_servers = [["localhost", "localhost:6600:"]];
+ 
+ var mpd = {
+     _host : null,
+     _port : null,
+     _password : null,
+     
+     // Output of status
+     volume : null,
+     repeat : null,
+     random : null,
+     playlistlength : 0,
+     playlist : 0,
+     xfade : null,
+     state : null,
+     song : null,
+     songid : null,
+     time : null,
+     bitrate : null,
+     updating_db : null,
+     
+     // Output of currentsong
+     file : null,
+     Time : null,
+     Artist : null,
+     Title : null,
+     sbTitle : null,
+     Album : null,
+     Track : null,
+     Date : null,
+     Genre : null,
+     Composer : null,
+     currentsong : {}, // All values as object. Observe this if you need
+                         // multiple properties.
+     
+     db_update : null,
+     sec_ticks : 0,
+     sec_synced : false,
+     update_interval : nsMPM.prefs.get("update_interval", 200),
+     adaptive_interval : nsMPM.prefs.get("adaptive_interval", true),
+     playlistname : nsMPM.translateService.GetStringFromName("new_playlist"),
+     
+     // Playlist contents and total playtime
+     plinfo : [],
+     pltime : 0,
+     prettytime: '',
+     pl_lookup : {},
+     
+     // Connection state information
+     greeting : nsMPM.translateService.GetStringFromName('not_connected'),
+     last_command : '',
+     lastResponse : '',
+     _idle : false,
+     _doStatus : true,
+     _timer : null,
+     _cmdQueue : [],
+     _socket : null,
+     
+     cachedArt : [],
+     cachedDB : [],
+     servers : [["localhost", "localhost:6600:"]]
+ }
+ 
+ mpd._checkStatus = function() {
+     nsMPM.mpd._doStatus = true
+     var tm = (nsMPM.mpd.state != 'play') ? 1500 : nsMPM.mpd.update_interval
+     if (nsMPM.mpd._timer) {
+         nsMPM.mpd._timer.cancel()
+     }
+     if (!nsMPM.mpd._socket) {
+         nsMPM.mpd._socket = socketTalker()
+     }
+     if (nsMPM.mpd._idle) {
+         nsMPM.mpd.doCmd("ping", null, true)
+     }
+     if (nsMPM.mpd._socket) {
+         var cb = {
+             notify : function(tmr) {
+                 nsMPM.mpd._checkStatus()
+             }
+         }
+         nsMPM.mpd._timer = Components.classes["@mozilla.org/timer;1"]
+                 .createInstance(Components.interfaces.nsITimer)
+         nsMPM.mpd._timer.initWithCallback(cb, tm,
+                 Components.interfaces.nsITimer.TYPE_ONE_SHOT)
+     }
+ }
+ 
+ // Parse output from currentsong nsMPM.mpd.doCmd, internal use only.
+ mpd._parseCurrentSong = function(data) {
+     // parse the incoming data into a status object
+     var obj = new Object()
+     data = data.split("\n")
+     var dl = data.length
+     var pair
+     do {
+         var sep = data[dl - 1].indexOf(": ")
+         if (sep > 0) {
+             obj[data[dl - 1].substr(0, sep)] = data[dl - 1].slice(sep + 2)
+         }
+     } while (--dl)
+ 
+     // React to and alter certain values.
+     if (nsMPM.Nz(obj.file)) {
+         if (nsMPM.Nz(obj.Title, '') == '') {
+             if (nsMPM.prefs.get("guess_tags", false)) obj = nsMPM.guessTags(obj)
+             else obj.Title = obj.file.split("/").pop()
+         }
+         obj.type = 'file'
+         obj.name = obj.file
+     }
+ 
+     // set currentsong values
+     nsMPM.mpd.set('Time', nsMPM.Nz(obj.Time))
+     nsMPM.mpd.set('Artist', nsMPM.Nz(obj.Artist))
+     nsMPM.mpd.set('Title', nsMPM.Nz(obj.Title))
+     nsMPM.mpd.set('sbTitle', nsMPM.Nz(obj.Title))
+     nsMPM.mpd.set('Album', nsMPM.Nz(obj.Album))
+     nsMPM.mpd.set('Track', nsMPM.Nz(obj.Track))
+     nsMPM.mpd.set('Date', nsMPM.Nz(obj.Date))
+     nsMPM.mpd.set('Genre', nsMPM.Nz(obj.Genre))
+     nsMPM.mpd.set('Composer', nsMPM.Nz(obj.Composer))
+     nsMPM.mpd.set('currentsong', obj)
+     nsMPM.mpd.set('file', nsMPM.Nz(obj.file))
+ }
+ 
+ mpd._parseDB = function(data) {
+     data = data.split("\n")
+     var db = []
+     var dl = data.length
+     var guess = nsMPM.prefs.get("guess_tags", false)
+     if (dl > 0) {
+         var n = dl
+         do {
+             var i = dl - n
+             var sep = data[i].indexOf(": ")
+             if (sep > -1) {
+                 var fld = data[i].substr(0, sep)
+                 var val = data[i].slice(sep + 2)
+                 if (fld == 'file') {
+                     var song = {
+                         type : 'file',
+                         file : val,
+                         name : val,
+                         Track : '',
+                         Title : '',
+                         Artist : '',
+                         Album : '',
+                         Time : 0,
+                         Pos : null,
+                         Id: null
+                     };
+                     var d = data[i + 1]
+                     while (d && d.charCodeAt(0) < 97) {
+                         var sep = d.indexOf(": ")
+                         song[d.substr(0, sep)] = d.slice(sep + 2);
+                         --n;
+                         var d = data[dl - n + 1]
+                     };
+                     if (song.Title == '') {
+                         if (guess) song = nsMPM.guessTags(song)
+                         else song.Title = val.split("/").pop()
+                     }
+                     db.push(song);
+                 } else {
+                     if (fld == 'directory') {
+                         var dir = val.split("/")
+                         db.push({
+                             type : 'directory',
+                             name : val,
+                             Title : dir[dir.length - 1],
+                             file : val
+                         })
+                     } else {
+                         var x = {
+                             type : fld,
+                             name : val,
+                             Title : val
+                         }
+                         x[fld] = val
+                         db.push(x)
+                     }
+                 }
+             }
+         } while (--n)
+     }
+     return db
+ }
+ 
+ mpd._parsePL = function(data) {
+     try {
+         nsMPM.debug("_parsePL: playlist="+mpd.playlist)
+         var db = nsMPM.mpd._parseDB(data, false)
+         if (db.length == 0) nsMPM.mpd._parseCurrentSong("")
+         if (db.length > 0) {
+             var i = db.length - 1
+             do {
+                 nsMPM.mpd.plinfo[db[i].Pos] = db[i]
+                 nsMPM.mpd.pl_lookup[db[i].file] = db[i].Pos
+             } while (i--)
+         }
+         var l = nsMPM.mpd.plinfo.length
+         var tm = 0
+         if (l > 0) {
+             var n = l
+             do {
+                 var item = nsMPM.Nz(nsMPM.mpd.plinfo[l - n])
+                 if (item)
+                     tm += parseInt(nsMPM.mpd.plinfo[l - n].Time)
+                 else {
+                     nsMPM.debug("Missing playlist item " + (l - n)
+                             + " when calculating time.")
+                     nsMPM.mpd.playlist = 0
+                 }
+             } while (--n)
+         }
+         nsMPM.mpd.set("pltime", tm)
+         nsMPM.observerService.notifyObservers(null, "plinfo", db.length)
+         nsMPM.mpd.set("playlistlength", nsMPM.mpd.playlistlength)
+         nsMPM.mpd.set("prettytime", nsMPM.prettyTime(tm))
+         if (nsMPM.mpd.playlistlength == 0) {
+             nsMPM.mpd.set("playlistname", nsMPM.translateService.GetStringFromName("new_playlist"))
+         } else {
+             if (nsMPM.mpd.playlistname == nsMPM.translateService.GetStringFromName("new_playlist")) nsMPM.mpd.guessPlaylistName()
+         }
+     } catch (e) {
+         nsMPM.debug(e);
+         nsMPM.mpd.playlist = 0
+     }
+ }
+ 
+ // Parse output from status nsMPM.mpd.doCmd, internal use only.
+ mpd._update = function(data) {
+     try {
+         // parse the incoming data into a status object
+         var obj = new Object()
+         data = data.split("\n")
+         var dl = data.length
+         var pair
+         do {
+             pair = data[dl - 1].split(": ", 2)
+             if (pair.length == 2) {
+                 obj[pair[0]] = pair[1]
+             }
+         } while (--dl)
+ 
+         // React to and alter certain values.
+         var t = nsMPM.Nz(obj.time, '0:0').split(":")
+         if (obj.state == 'stop') {
+             obj.time = 0
+         } else {
+             obj.time = t[0]
+         }
+ 
+         // Adaptive update intervals. Run updates at 200 ms until we are
+         // updating in sync with the time, then switch to 1000 ms.
+         if (nsMPM.mpd.state == 'play' && nsMPM.mpd.adaptive_interval) {
+             if (obj.time == nsMPM.mpd.time) {
+                 nsMPM.mpd.sec_ticks++
+             } else {
+                 if (nsMPM.mpd.update_interval == 1000) {
+                     nsMPM.mpd.sec_synced = (nsMPM.mpd.sec_ticks < 2)
+                 } else {
+                     nsMPM.mpd.sec_synced = (nsMPM.mpd.sec_ticks == 4)
+                     nsMPM.mpd.sec_ticks = 0
+                 }
+             }
+             nsMPM.mpd.update_interval = (nsMPM.mpd.sec_synced) ? 1000 : 200
+         }
+ 
+         if (obj.songid != nsMPM.mpd.songid) {
+             nsMPM.mpd.doCmd("currentsong", nsMPM.mpd._parseCurrentSong, true)
+         } else {
+             CS = false
+             if (obj.song <= nsMPM.mpd.plinfo.length) {
+                 CS = nsMPM.Nz(nsMPM.mpd.plinfo[obj.song])
+                 if (CS.file.indexOf("://") > 0) {
+                     if (CS.Title != nsMPM.mpd.Title){
+                         nsMPM.mpd.doCmd("currentsong", nsMPM.mpd._parseCurrentSong, true)
+                     }
+                 }
+             }
+         }
+         nsMPM.mpd.playlist = nsMPM.Nz(nsMPM.mpd.playlist, 0)
+         if (obj.playlist != nsMPM.mpd.playlist) {
+             var l = parseInt(nsMPM.Nz(obj.playlistlength, 0))
+             if (l < nsMPM.mpd.plinfo.length && nsMPM.Nz(nsMPM.mpd.pl_lookup)) {
+                 var new_lookup = {}
+                 for (x in nsMPM.mpd.pl_lookup) {
+                     if (nsMPM.mpd.pl_lookup[x] < l) new_lookup[x] = nsMPM.mpd.pl_lookup[x]
+                 }
+                 nsMPM.mpd.pl_lookup = new_lookup
+             }
+             nsMPM.mpd.plinfo.length = l
+             var cmd = (nsMPM.mpd.playlist > 0)
+                     ? "plchanges " + nsMPM.mpd.playlist
+                     : "playlistinfo"
+             nsMPM.mpd.doCmd(cmd, nsMPM.mpd._parsePL, true)
+         }
+         nsMPM.mpd.playlist = nsMPM.Nz(obj.playlist)
+         if (nsMPM.mpd.updating_db) {
+             if (!nsMPM.Nz(obj.updating_db)) {
+                 nsMPM.mpd.set('updating_db', null)
+                 nsMPM.mpd.cachedDB = []
+             }
+         }
+ 
+         // set status values
+         nsMPM.mpd.set('volume', nsMPM.Nz(obj.volume))
+         nsMPM.mpd.set('repeat', nsMPM.Nz(obj.repeat))
+         nsMPM.mpd.set('random', nsMPM.Nz(obj.random))
+         nsMPM.mpd.set('playlistlength', nsMPM.Nz(obj.playlistlength))
+         nsMPM.mpd.set('xfade', nsMPM.Nz(obj.xfade))
+         nsMPM.mpd.set('state', nsMPM.Nz(obj.state))
+         nsMPM.mpd.set('song', nsMPM.Nz(obj.song))
+         nsMPM.mpd.set('time', nsMPM.Nz(obj.time))
+         nsMPM.mpd.set('bitrate', nsMPM.Nz(obj.bitrate))
+         nsMPM.mpd.set('updating_db', nsMPM.Nz(obj.updating_db))
+         nsMPM.mpd.set('db_update', nsMPM.Nz(obj.db_update))
+ 
+         nsMPM.mpd._doStatus = false
+     } catch (e) {
+         nsMPM.debug(e)
+     }
+ }
+ 
+ mpd.addToPlaylist = function(itemArray) {
+     // Input should be an array of db objects or a single db object.
+     if (typeof(itemArray[0]) != 'object')
+         itemArray = [itemArray]
+     var l = itemArray.length
+     var cmd = "command_list_begin"
+     var hasFiles = false
+     for (var i = 0; i < l; i++) {
+         var item = itemArray[i]
+         if (item.type == 'file' || item.type == 'directory') {
+             hasFiles = true
+             cmd += '\nadd ' + nsMPM.Sz(item.name)
+         } else {
+             var q = new nsMPM.dbQuery()
+             q.type = 'file'
+             q.scope = item.type
+             q.query = item.name
+             q.callBack = function(db) {
+                 var dbl = db.length
+                 var c = "command_list_begin"
+                 for (var x = 0; x < dbl; x++) {
+                     c += '\nadd ' + nsMPM.Sz(db[x].name)
+                 }
+                 nsMPM.mpd.doCmd(c + "\ncommand_list_end")
+             }
+             q.execute()
+         }
+     }
+     if (hasFiles) {
+         hasFiles = false
+         nsMPM.mpd.doCmd(cmd + "\ncommand_list_end")
+         cmd = "command_list_begin"
+     }
+ }
+ // Connection methods
+ mpd.connect = function() {
+     if (nsMPM.mpd._timer) {
+         nsMPM.mpd._timer.cancel()
+         nsMPM.mpd._timer = null
+     }
+     if (nsMPM.mpd._socket) {
+         nsMPM.mpd._socket.cancel()
+         nsMPM.mpd._socket = null
+     }
+     if (nsMPM.mpd._host && nsMPM.mpd._port) {
+         nsMPM.mpd.set("playlistname", nsMPM.translateService.GetStringFromName("new_playlist"))
+         nsMPM.mpd._checkStatus()
+     } else
+         nsMPM.mpd.set("lastResponse", nsMPM.translateService.GetStringFromName("server_not_selected"))
+ }
+ 
+ mpd.force_connect = function() { let that = this; that.loadSrvPref() }
+ mpd.disconnect = function() {
+     if (nsMPM.mpd._timer) {
+         nsMPM.mpd._timer.cancel()
+         nsMPM.mpd._timer = null
+     }
+     if (nsMPM.mpd._socket) {
+         nsMPM.mpd._socket.cancel()
+         nsMPM.mpd._socket = null
+     }
+     nsMPM.mpd._host = null
+     nsMPM.mpd._port = null
+ }
+ 
+ // Talk directlty to MPD, outputData must be properly escaped and quoted.
+ // callBack is optional, if left out or null and no socket is in use,
+ // a single use connection will be made for this nsMPM.mpd.doCmd.
+ mpd.doCmd = function(outputData, callBack, hide, priority) {
+     
+     hide = nsMPM.Nz(hide)
+     priority = nsMPM.Nz(priority)
+     if (/^rename\ |^rm\ |^save\ /m.test(outputData)) {
+         callBack = function(d) {
+             nsMPM.observerService.notifyObservers(null, 'playlists', null)
+         }
+     }
+     if (/^\s*load\s/m.test(outputData)) {
+         var name = /^\s*load\s+\"(.+)\"\s*$/m.exec(outputData)
+         nsMPM.debug(outputData)
+         if (name) {
+             nsMPM.mpd.set("playlistname", name[1])
+         }
+     }
+     if (priority) {
+         nsMPM.debug("priority command: " + outputData)
+         nsMPM.mpd._cmdQueue.unshift({
+             outputData : outputData + "\n",
+             callBack : nsMPM.Nz(callBack),
+             hide : hide,
+             sent : false
+         })
+     } else {
+         nsMPM.mpd._cmdQueue.push({
+             outputData : outputData + "\n",
+             callBack : nsMPM.Nz(callBack),
+             hide : hide,
+             sent : false
+         })
+     }
+     if (nsMPM.mpd._socket) {
+         nsMPM.mpd._doStatus = true
+         if (nsMPM.mpd._idle) {
+             nsMPM.mpd._socket.writeOut(nsMPM.mpd._cmdQueue[0].outputData)
+             if (!hide)
+                 nsMPM.mpd.set('last_command', outputData);
+             nsMPM.mpd._idle = false
+         }
+     } else {
+         nsMPM.mpd.connect()
+     }
+ }
+ 
+ mpd.getAllDirs = function(callBack) {    
+     if (!nsMPM.mpd._socket)
+         nsMPM.mpd.connect()
+     var cb = callBack
+     nsMPM.mpd.doCmd("listall", function(d) {
+         try {
+             d = d.replace(/^file: .*\n/gm, "")
+             d = d.replace(/^directory: /gm, "")
+             d = d.replace(/^\//gm, "")
+             dirs = d.split("\n").sort().slice(1)
+             var hd = []
+             var l = dirs.length
+             if (l < 1) {
+                 nsMPM.debug("EMPTY getAllDirs() CALLBACK!");
+                 return []
+             }
+             var n = l
+             do {
+                 var name = dirs[l - n]
+                 var path = name.split("/")
+                 var obj = {
+                     Title : path.pop(),
+                     level : path.length,
+                     parent : path.join("/"),
+                     name : name,
+                     type : 'directory',
+                     children : 0
+                 }
+                 if (obj.level > 0) {
+                     for (var pi = hd.length - 1; pi > -1; pi--) {
+                         if (hd[pi].name == obj.parent) {
+                             hd[pi].children += 1
+                             break
+                         }
+                     }
+                 }
+                 hd.push(obj)
+             } while (--n)
+             cb(hd)
+         } catch (e) {
+             nsMPM.debug(e)
+         }
+         return 'undefined';
+     })
+ }
+ 
+ mpd.getArt = function(item, img) {
+ 	var fallback = function (code, item, url) {
+ 		try{
+ 			if ( code == 200 || code == 0 ) {
+ 				nsMPM.mpd.cachedArt[url] = url;
+ 				img.setAttribute("tooltiptext",url);
+ 				img.src = url;
+ 				return;
+ 			}
+ 			if (nsMPM.prefs.get("use_amazon_art", 1) >= 1 ) {
+ 				nsMPM.getAmazonArt(nsMPM.mpd, item, img);
+ 			} else {
+ 				img.src = "chrome://minion/content/images/album_blank.png";
+ 				img.removeAttribute("tooltiptext");
+ 			}
+ 		} catch(e){ nsMPM.debug(e); }
+ 	};
+ 
+ 	try {
+ 		if ( typeof(item.file) != 'string' ) {
+ 			var art =  "chrome://minion/content/images/album_blank.png";
+ 			img.src = art;
+ 			img.setAttribute("tooltiptext",art);
+ 			return;
+ 		}
+ 
+ 		var strFile = new String(item.file);
+ 		if ( strFile.indexOf('http://') == 0 || strFile.indexOf('https://') == 0 ) {
+ 			var art =  "chrome://minion/content/images/internet_music.png";
+ 			img.src = art;
+ 			img.setAttribute("tooltiptext",art);
+ 			return;
+ 		}
+ 		
+ 		img.src = "chrome://minion/content/images/album_loading.png";
+ 		img.setAttribute("tooltiptext","...");
+ 		
+ 		if (nsMPM.prefs.get("use_custom_art", false)) {
+ 			var url = nsMPM.urlReplace(nsMPM.prefs.get("custom_art_url"), item)
+ 			nsMPM.debug("Attempting to fetch cover at " + url);
+ 			if (typeof(nsMPM.mpd.cachedArt[url]) != 'string') nsMPM.prefetchImageFromURL(url, fallback, item);
+ 			else {
+ 				img.setAttribute("tooltiptext",url);
+ 				img.src = url;
+ 			}
+ 		} else {
+ 			fallback(404, item);
+ 		}
+ 	} catch(e) { nsMPM.debug(e); }
+ }
+ 
+ mpd.guessPlaylistName = function () {
+     var playlists = []
+     var aCurPL = []
+     var plinfo = nsMPM.mpd.plinfo
+     
+     for (x=0, l=plinfo.length; x<l; x++) {
+         aCurPL.push(plinfo[x].file)
+     }
+     var currentPL = "file: " + aCurPL.join("\nfile: ") + "\n"
+     
+     var nextPL = function () {
+         pl = playlists.shift().replace(/"/g, '\\"')
+         nsMPM.mpd.doCmd('listplaylist "'+pl+'"', function(data){
+             if (data==currentPL) {
+                 nsMPM.mpd.set("playlistname", pl)
+             } else {
+                 if (playlists.length > 0) nextPL()
+             }
+         }, false)
+     }
+     
+     var q = new nsMPM.dbQuery()
+     q.type = "playlist"
+     q.query = ""
+     q.execute(function(db){
+         for (i in db) playlists.push(db[i].Title)
+         if (playlists.length > 0) nextPL()
+     })
+ }
+     
+ mpd.searchLyrics = function (q, origCallBack) {
+     q = q.replace(/[^A-Za-z0-9]/g, '%')
+     var url = "http://lyricsfly.com/api/txt-api.php?i={id}&i=" + q
+     url = url.replace("{id}", "14f6b319c854ca8a8-temporary.API.access")
+     //url = url.replace("{id}", nsMPM.prefs.get("lyricsfly_id",""))
+     //url = url.replace("{amo}", "addons.mozilla.org/en-US/firefox/addon/6324")
+     
+     var cb = function(data) {
+         try {
+             var ar = data.getElementsByTagName("ar")
+             var tt = data.getElementsByTagName("tt")
+             nsMPM.debug(tt)
+             var artists = []
+             var titles = []
+             var cmd = null
+             if (tt) {
+                 cmd = "command_list_begin\n"
+                 for (i=0;i<tt.length;i++) {
+                     titles.push(tt[i].textContent)
+                     artists.push(ar[i].textContent)
+                     cmd += 'find title "'+titles[i]+'"\n'
+                 }
+                 cmd += "command_list_end\n"
+             }
+         }
+         catch (e) {nsMPM.debug(e)}
+         if (cmd) {
+             nsMPM.debug(cmd)
+             var db_cb = function (d) {
+                 var db = nsMPM.mpd._parseDB(d)
+                 nsMPM.debug(d)
+                 for (i=0;i<db.length;i++) {
+                     var x = titles.indexOf(db[i].Title)
+                     if (x > -1 && db[i].Artist != artists[x]) {
+                         db.splice(i,1)
+                     }
+                 }
+                 origCallBack(db)
+             }
+             nsMPM.mpd.doCmd(cmd, db_cb)
+         }
+     }
+     nsMPM.debug(url)
+     nsMPM.fetch(url, cb, null, true)
+ }
+ 
+ mpd.getLyrics = function (item, txtLyrics, btnEdit) {
+     if (!nsMPM.Nz(item.Artist)) {
+         txtLyrics.value = nsMPM.translateService.GetStringFromName("no_lyrics_found");
+         btnEdit.edit_link = "http://lyricsfly.com/submit/"
+         return
+     }
+     var cb = function(data) {
+         var lyrics = nsMPM.translateService.GetStringFromName("no_lyrics");
+         try {
+             var tx = data.getElementsByTagName("tx")
+             if (nsMPM.Nz(tx[0])) {
+                 var lyrics = tx[0].textContent.replace(/\[br\]/g,"")
+                 var cs = data.getElementsByTagName("cs")
+                 var id = data.getElementsByTagName("id")
+                 if (nsMPM.Nz(cs[0]) && nsMPM.Nz(id[0]) && nsMPM.Nz(btnEdit)) {
+                     var ed = "http://lyricsfly.com/search/correction.php?[CHECKSUM]&id=[SONG ID]"
+                     ed = ed.replace("[CHECKSUM]", cs[0].textContent)
+                     ed = ed.replace("[SONG ID]", id[0].textContent)
+                     btnEdit.edit_link = ed
+                 }
+             }
+         }
+         catch (e) {nsMPM.debug(e)}
+         finally { txtLyrics.value = lyrics }
+     }
+     var url = "http://lyricsfly.com/api/api.php?i={id}-{amo}&a={Artist}&t={Title}"
+     // Please do not attempt to use this user id for api access.
+     // It is easy to obtain your own id, please see http://lyricsfly.com/api/
+     url = url.replace("{id}", nsMPM.prefs.get("lyricsfly_id",""))
+     url = url.replace("{amo}", "addons.mozilla.org/en-US/firefox/addon/6324")
+     url = url.replace("{Artist}", nsMPM.Nz(item.Artist, '').replace(/[^A-Za-z0-9]/g, '%'))
+     url = url.replace("{Title}", nsMPM.Nz(item.Title, '').replace(/[^A-Za-z0-9]/g, '%'))
+     txtLyrics.value = nsMPM.translateService.GetStringFromName("searching_lyrics");
+     btnEdit.edit_link = "http://lyricsfly.com/submit/"
+     nsMPM.fetch(url, cb, null, true)
+ }
+ 
+ mpd.getOutputs = function(callBack) {
+     var cb = function(data) {
+         // Parse the incoming data into an array of output objects
+         var obj = []
+         data = data.split("\n")
+         var dl = data.length - 2
+         for (var i = 0; i < dl; i++) {
+             var sep = data[i].indexOf(": ")
+             if (sep > 0) {
+                 var idx = data[i].slice(sep + 2)
+                 var name = "unknown"
+                 var enabled = false
+                 sep = data[++i].indexOf(": ")
+                 if (sep > 0) {
+                     name = data[i].slice(sep + 2)
+                     sep = data[++i].indexOf(": ")
+                     if (sep > 0) {
+                         enabled = (data[i].slice(sep + 2) == 1) ? true : false
+                     }
+                 }
+                 obj[idx] = {
+                     id : idx,
+                     name : name,
+                     enabled : enabled
+                 }
+             }
+         }
+         callBack(obj)
+     }
+     nsMPM.mpd.doCmd('outputs', cb)
+ }
+ 
+ mpd.setServers = function(servers) {
+ 	nsMPM.mpd.set('servers', servers);
+ 	try {
+ 		var file = nsMPM.DirIO.get(nsMPM.pref_dir);
+ 		file.append(nsMPM.pref_file_servers);
+ 		if (!file.exists()) {
+ 			nsMPM.FileIO.create(file);
+ 		}
+ 		var str = nsMPM.JSON.stringify(nsMPM.mpd.servers);
+ 		nsMPM.FileIO.write(file, str);
+ 		file = null;
+ 	} catch(e) { nsMPM.debug(e); }
+ }
+ 
+ mpd.loadServers = function() {
+ 	var file = nsMPM.DirIO.get(nsMPM.pref_dir);
+ 	file.append(nsMPM.pref_file_servers);
+ 	if (file.exists()) {
+ 		nsMPM.debug("Reading server nsMPM.prefs from: "+file.path);
+ 		var str = nsMPM.FileIO.read(file);
+ 		nsMPM.mpd.servers = nsMPM.JSON.parse(str);
+ 	} else {
+ 		// creating default server
+ 		var s,p;
+ 		if ( nsMPM.env.exists('MPD_HOST') ) {
+ 			s = nsMPM.env.get('MPD_HOST');
+ 			if ( nsMPM.env.exists('MPD_PORT')) {
+ 				p = nsMPM.env.get('MPD_PORT');
+ 			} else {
+ 				p = 6600; // this is the default mpd port
+ 			}
+ 			nsMPM.debug('Found MPD environment settings');
+ 			nsMPM.mpd.servers = [[s, s+':'+p+':']]
+ 			nsMPM.mpd.setServers(nsMPM.mpd.servers);
+ 			nsMPM.prefs.set("server",nsMPM.mpd.servers[0][1]);
+ 		} else {
+ 			nsMPM.debug("Creating default servers.");
+ 			nsMPM.mpd.servers = default_servers;
+ 			nsMPM.mpd.setServers(nsMPM.mpd.servers);
+ 			nsMPM.prefs.set("server",nsMPM.mpd.servers[0][1]);
+ 		}
+ 	}
+ 	file = null;
+ }
+ 
+ // Any property that may be observed must be set with this method.
+ mpd.set = function(prop, val) {
+     if (val != nsMPM.mpd[prop]) {
+         //nsMPM.debug("Notify: nsMPM.mpd."+prop+" = "+val)
+         nsMPM.mpd[prop] = val
+         nsMPM.observerService.notifyObservers(null, prop, val)
+     }
+ }
+ 
+ mpd.toggleRandom = function() {
+     var state = (nsMPM.mpd.random > 0) ? 0 : 1
+     nsMPM.mpd.doCmd("random " + state)
+ }
+ 
+ mpd.toggleRepeat = function() {
+     var state = (nsMPM.mpd.repeat > 0) ? 0 : 1
+     nsMPM.mpd.doCmd("repeat " + state)
+ }
+ 
+ mpd.load_pls_stream = function(data, action) {
+ 	try {
+ 		var itemCount=0;
+ 		if (typeof(action) == 'undefined') action = "add";
+ 		var urls = data.match(/(?:File\d+=)(.+)(?:[\n|\r])/ig)
+ 		var cmd = 'command_list_begin'
+ 		if (action == "replace") cmd += "\nclear";
+ 		for (x in urls) {
+ 			var u = urls[x].replace("\n", "").replace(/File\d+=/gi, "")
+ 			if (u.length > 0) {
+ 				cmd += '\nadd ' + u;
+ 				itemCount++;
+ 			}
+ 		}
+ 		cmd += '\ncommand_list_end'
+ 		nsMPM.mpd.doCmd(cmd)
+ 	} catch(e){ nsMPM.debug(e); }
+ 	return itemCount;
+ }
+ 
+ mpd.load_m3u_stream = function(data, action) {
+ 	try {
+ 		var itemCount=0;
+ 		if (typeof(action) == 'undefined') action = "add"
+ 		urls = data.replace(/^#.+$/mg, "").replace(/\r/mg,'').split("\n")
+ 		var cmd = 'command_list_begin';
+ 		if (action == "replace") cmd += "\nclear";
+ 		for (x in urls) {
+ 			var u = urls[x];
+ 			if (u.length > 0) {
+ 				cmd += '\nadd ' + u;
+ 				itemCount++;
+ 			}
+ 		}
+ 		cmd += '\ncommand_list_end';
+ 		nsMPM.mpd.doCmd(cmd);
+ 	} catch(e){ nsMPM.debug(e); }
+ 	return itemCount;
+ }
+ 
+ mpd.load_xspf_stream = function(data, action) {
+ 	try {
+ 		var itemCount=0;
+ 		if (typeof(action) == 'undefined') action = "add";
+ 		urls = data.getElementsByTagName("location");
+ 		var cmd = 'command_list_begin';
+ 		if (action == "replace") cmd += "\nclear";
+ 		for (var x=0; x < urls.length; x++) {
+ 			var u = urls.item(x);
+ 			if ( u.textContent.length > 0 ) {
+ 				cmd += '\nadd ' + u.textContent;
+ 				itemCount++;
+ 			}
+ 		}
+ 		cmd += '\ncommand_list_end';
+ 		nsMPM.mpd.doCmd(cmd);
+ 	} catch(e){ nsMPM.debug(e); }
+ 	return itemCount;
+ }
+ 
+ mpd.prefObserver = {
+ 	obs: null,
+ 	register : function() {
+ 		this.obs = nsMPM.prefs.getObserver("server",nsMPM.mpd.loadSrvPref);
+ 	},
+ 	unregister : function() {
+ 		this.obs.unregister();
+ 	}
+ }
+ 
+ mpd.loadSrvPref = function() {
+ 	var srv = ''
+ 	if (nsMPM.prefs.isPref("server") == true) {
+ 		var srv = nsMPM.prefs.get("server",default_servers[0]);
+ 	}
+ 	nsMPM.debug('srv = '+srv)
+ 	if (srv > '') {
+ 		srv = srv.split(":", 3);
+ 		var cb = function() {
+ 			nsMPM.mpd._cmdQueue = [];
+ 			if (srv.length == 3) {
+ 				nsMPM.mpd._host = srv[0];
+ 				nsMPM.mpd._port = parseInt(srv[1]);
+ 				nsMPM.mpd._password = srv[2];
+ 				nsMPM.mpd.connect();
+ 				nsMPM.observerService.notifyObservers(null, "new_mpd_server", srv[0] + ":" + srv[1]);
+ 			} else {
+ 				nsMPM.mpd._host = null;
+ 				nsMPM.mpd._port = null;
+ 				nsMPM.observerService.notifyObservers(null, "new_mpd_server", null);
+ 			}
+ 		}
+ 		var timer = Components.classes["@mozilla.org/timer;1"]
+ 					.createInstance(Components.interfaces.nsITimer);
+ 		nsMPM.mpd.disconnect();
+ 		timer.initWithCallback(cb, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+ 	} else {
+ 		nsMPM.debug("No server, disconnecting.");
+ 		nsMPM.mpd.disconnect();
+ 	}
+ }
+ 
+ function socketTalker() {
+     if (nsMPM.mpd._port <= '' || nsMPM.mpd._host <= '') return null
+     nsMPM.debug("enter socketTalker")
+     nsMPM.mpd.set('greeting', 'Connecting...');
+     var initialized = false
+     var regGreet = /OK MPD [0-9\.]+\n/gm
+     try {
+         var transportService = Components.classes["@mozilla.org/network/socket-transport-service;1"]
+                 .getService(Components.interfaces.nsISocketTransportService);
+         var transport = transportService.createTransport(null, 0, nsMPM.mpd._host,
+                 nsMPM.mpd._port, null);
+         var outstream = transport.openOutputStream(0, 0, 0);
+         var instream = transport.openInputStream(0, 0, 0);
+         const replacementChar = Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
+         var utf_instream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
+                 .createInstance(Components.interfaces.nsIConverterInputStream);
+         var utf_outstream = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
+                 .createInstance(Components.interfaces.nsIConverterOutputStream)
+ 
+         utf_instream.init(instream, 'UTF-8', 1024, replacementChar);
+         utf_outstream.init(outstream, 'UTF-8', 0, 0x0000)
+     } catch (e) {
+         nsMPM.mpd._host = null
+         nsMPM.mpd._port = null
+         nsMPM.mpd._password = null
+         nsMPM.mpd.disconnect()
+         return null
+     }
+ 
+     var listener = {
+         data : "",
+         onStartRequest : function(request, context) {
+             nsMPM.mpd._idle = false
+             nsMPM.mpd.cachedDB = []
+             initialized = false
+             nsMPM.debug('socketTalker for server ' + nsMPM.mpd._host + ":" + nsMPM.mpd._port
+                     + " created.")
+             nsMPM.mpd.set('greeting', nsMPM.translateService.GetStringFromName('connecting'));
+         },
+         onStopRequest : function(request, context, status) {
+             this.data = null
+             nsMPM.debug('socketTalker for server ' + nsMPM.mpd._host + ":" + nsMPM.mpd._port
+                     + " destroyed.")
+             nsMPM.debug('close status = ' + status)
+             nsMPM.mpd._socket = null
+             nsMPM.mpd.set('greeting', nsMPM.translateService.GetStringFromName('not_connected'));
+             if (status == NOSRV_STATUS) {
+                 nsMPM.mpd._host = null
+                 nsMPM.mpd._port = null
+                 nsMPM.mpd._password = null
+                 nsMPM.debug("Killing socket")
+             }
+         },
+         onDataAvailable : function(request, context, inputStream, offset, count) {
+             try {
+                 nsMPM.mpd._idle = false
+                 var str = {};
+                 var chunks = []
+                 var chlen = 0
+                 var done = false
+                 while (utf_instream.readString(4096, str) != 0) {
+                     chunks[chlen++] = str.value
+                 }
+                 this.data += chunks.join("")
+                 str = null
+                 if (!initialized) {
+                     var greet = this.data.match(regGreet)
+                     if (greet) {
+                         initialized = true
+                         this.data = this.data.replace(regGreet, "")
+                         nsMPM.mpd.set('greeting', "MPD@" + nsMPM.mpd._host
+                                 + ":" + nsMPM.mpd._port)
+                         if (nsMPM.mpd._password.length > 0) {
+                             nsMPM.mpd._cmdQueue.unshift({
+                                 outputData : 'password "' + nsMPM.mpd._password
+                                         + '"\n',
+                                 callBack : null,
+                                 hide : true
+                             })
+                         }
+                         if (nsMPM.mpd._cmdQueue.length > 0) {
+                             var snd = nsMPM.mpd._cmdQueue[0].outputData
+                             utf_outstream.writeString(snd);
+                             if (!nsMPM.mpd._cmdQueue[0].hide) {
+                                 nsMPM.mpd.set('last_command', snd);
+                                 nsMPM.mpd.set('lastResponse', nsMPM.translateService.GetStringFromName("working"));
+                             } else if (snd.slice(0, 9) == "plchanges") {
+                                 nsMPM.mpd.set('lastResponse', nsMPM.translateService.GetStringFromName("working"));
+                             }
+                         } else {
+                             done = true
+                         }
+                         nsMPM.observerService.notifyObservers(null, "new_connection",
+                                 null)
+                     }
+                 }
+                 if (this.data.substr(-3) == "OK\n") {
+                     var cdata = this.data.split(/^OK\n/gm)
+                     this.data = ""
+                     while (cdata.length > 1) {
+                         var d = cdata.shift()
+                         if (nsMPM.mpd._cmdQueue.length > 0) {
+                             var snd = nsMPM.mpd._cmdQueue[0].outputData
+                             if (!nsMPM.mpd._cmdQueue[0].hide) {
+                                 nsMPM.mpd.set('lastResponse', "OK");
+                             } else if (snd.slice(0, 9) == "plchanges") {
+                                 nsMPM.mpd.set('lastResponse', "OK");
+                             }
+                             if (nsMPM.mpd._cmdQueue[0].callBack) {
+                                 nsMPM.mpd._cmdQueue[0].callBack(d)
+                             }
+                             nsMPM.mpd._cmdQueue.shift()
+                         }
+                     }
+                     if (nsMPM.mpd._cmdQueue.length > 0) {
+                         var snd = nsMPM.mpd._cmdQueue[0].outputData
+                         utf_outstream.writeString(snd);
+                         if (!nsMPM.mpd._cmdQueue[0].hide) {
+                             nsMPM.mpd.set('last_command', snd);
+                             nsMPM.mpd.set('lastResponse', nsMPM.translateService.GetStringFromName("working"));
+                         } else if (snd.slice(0, 9) == "plchanges") {
+                             nsMPM.mpd.set('lastResponse', nsMPM.translateService.GetStringFromName("working"));
+                         }
+                     } else {
+                         done = true
+                     }
+                 } else if (this.data.indexOf('ACK [') != -1) {
+                     nsMPM.mpd.set('lastResponse', this.data.replace(/\n/g, ""))
+                     nsMPM.mpd._cmdQueue.shift()
+                     done = true
+                 }
+ 
+                 if (done) {
+                     if (nsMPM.mpd._doStatus) {
+                         nsMPM.mpd._doStatus = false
+                         nsMPM.mpd._cmdQueue.push({
+                             outputData : "command_list_begin\nstatus\nstats\ncommand_list_end\n",
+                             callBack : nsMPM.mpd._update,
+                             hide : true,
+                             sent : true
+                         })
+                         utf_outstream.writeString("command_list_begin\nstatus\nstats\ncommand_list_end\n")
+                     } else {
+                         nsMPM.mpd._idle = true
+                     }
+                 }
+             } catch (e) {
+                 nsMPM.mpd._host = null
+                 nsMPM.mpd._port = null
+                 nsMPM.mpd.disconnect()
+                 nsMPM.debug(e)
+             }
+         }
+     }
+ 
+     var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"]
+             .createInstance(Components.interfaces.nsIInputStreamPump);
+     pump.init(instream, -1, -1, 0, 0, false);
+     pump.asyncRead(listener, null);
+ 
+     var con = {
+         cancel : function() {
+             nsMPM.debug("Cancel socket")
+             transport.close(0)
+         },
+         writeOut : function(str) {
+             if (initialized)
+                 utf_outstream.writeString(str)
+         }
+     }
+ 
+     return con
+ } // end socketTalker()
+ 
+ 
+ function dbQuery(cmd, callBack) {
+     this.cmd = nsMPM.Nz(cmd);
+     this.path = [];
+     this.type = 'directory';
+     this.scope = null;
+     this.query = null;
+     this.restrict = null;
+     this.filterField = null;
+     this.filterQuery = null;
+     this.callBack = nsMPM.Nz(callBack);
+     this.dbMatches = null;
+ }
+ 
+ dbQuery.prototype.evaluate = function() {
+     if (this.cmd) {
+         var cmd = this.cmd
+         // Clean up and validate nsMPM.mpd.doCmd lists.
+         if (cmd.indexOf('command_list_begin') > -1) {
+             if (cmd.indexOf('command_list_end') < 0) {
+                 cmd += "\ncommand_list_end"
+             }
+         } else if (cmd.indexOf(';') > -1) {
+             cmd = "command_list_begin;" + cmd
+             if (cmd.indexOf('command_list_end') < 0) {
+                 cmd += ";command_list_end"
+             }
+             cmd = cmd.replace(/;/g, "\n")
+         }
+ 
+         // Check if this nsMPM.mpd.doCmd returns database results.
+         // If so, check if it will return multiple sets that
+         // will need to be combined.
+         var re = /^.*search |^.*find |^.*info|^plchanges |^list.* /gm
+         this.dbMatches = cmd.match(re)
+         this.cmd = cmd
+         return cmd
+     }
+ 
+     switch (this.type) {
+         case 'search' :
+             this.cmd = "search";
+             this.path = [{
+                 type : "search",
+                 Title : "Search (" + this.scope + "): " + this.query,
+                 name : this.query
+             }];
+             break;
+         case 'playlistsearch' :
+             this.cmd = "playlistsearch";
+             this.path = [{
+                 type : "playlistsearch",
+                 Title : "Search Playlist (" + this.scope + "): " + this.query,
+                 name : this.query
+             }];
+             break;
+         case 'directory' :
+             this.cmd = "lsinfo";
+             this.path = [{
+                 type : 'directory',
+                 Title : "Folders",
+                 name : ""
+             }];
+             if (nsMPM.Nz(this.query, "") == "") {
+                 this.restrict = ["directory", "file"];
+             }
+             var p = this.query.split("/");
+             if (p.length > 0) {
+                 for (var i = 0; i < p.length; i++) {
+                     if (p[i] > "") {
+                         this.path.push({
+                                     type : 'directory',
+                                     Title : p[i],
+                                     name : p.slice(0, i + 1).join("/")
+                                 })
+                     }
+                 }
+             }
+             break;
+         case 'file' :
+             this.cmd = "find";
+             this.path = [{
+                 type : this.scope,
+                 Title : this.scope + "s",
+                 name : ""
+             }, {
+                 type : this.scope,
+                 Title : this.query,
+                 name : this.query
+             }];
+             break;
+         case 'playlist' :
+             this.path = [{
+                 type : "playlist",
+                 Title : "Playlists",
+                 name : ""
+             }];
+             if (nsMPM.Nz(this.query, "") == "") {
+                 this.cmd = "lsinfo";
+                 this.restrict = "playlist";
+             } else {
+                 this.cmd = "listplaylistinfo";
+                 this.path.push({
+                             type : "playlist",
+                             Title : this.query,
+                             name : this.query
+                         });
+             }
+             ;
+             break;
+         case 'current_playlist' :
+             this.path = [{
+                 type : "playlist",
+                 Title : "Playlists",
+                 name : ""
+             }];
+             break;
+         default :
+             this.cmd = "list " + this.type;
+             this.path = [{
+                 type : this.type,
+                 Title : this.type + "s",
+                 name : ""
+             }];
+             break;
+     }
+     if (this.scope)
+         this.cmd += " " + this.scope;
+     if (this.query)
+         this.cmd += " " + nsMPM.Sz(this.query);
+     this.dbMatches = 1
+     return 'undefined';
+ }
+ 
+ dbQuery.prototype.execute = function(callBack) {
+     if (!nsMPM.mpd._socket) {
+         nsMPM.mpd.connect()
+         nsMPM.debug("dbQuery forcing connect.")
+     }
+     callBack = nsMPM.Nz(callBack, this.callBack)
+     this.evaluate()
+     var cmd = this.cmd
+     var path = this.path
+     var restrict = this.restrict
+     var useCache = !(this.type == 'playlist' || this.restrict)
+ 
+     if (nsMPM.Nz(nsMPM.mpd.cachedDB[cmd])) {
+         nsMPM.debug("cached: " + cmd)
+         callBack(nsMPM.mpd.cachedDB[cmd])
+         return null
+     }
+ 
+     if (!this.dbMatches) {
+         nsMPM.mpd.doCmd(cmd, null, false)
+         return null
+     } else {
+         var chkDupes = (this.dbMatches.length > 1)
+     }
+ 
+     if (this.filterField) useCache = false
+     var filterField = this.filterField
+     var filterQuery = this.filterQuery
+     var isPlaylists = (this.type=='playlist' && this.query=='')
+     nsMPM.mpd.doCmd(cmd, function(d) {
+         var db = nsMPM.mpd._parseDB(d)
+         if (restrict)
+             db = dbFilter(db, restrict)
+         if (chkDupes)
+             db = dbDistinct(db)
+         if (nsMPM.prefs.get("linguistic_sort", true) || isPlaylists) db.sort(nsMPM.smartsort)
+         if (useCache && db.length > 0)
+             nsMPM.mpd.cachedDB[cmd] = db
+         if (filterField) {
+             db = [x for each  (x in db) if (x[filterField]==filterQuery)]
+         }
+         callBack(db, path)
+     }, false)
+     return true
+ }
+ 
+ 
+ function dbDistinct(db) {
+     var rdb = []
+     var dl = db.length
+     if (dl < 1) {
+         return db
+     }
+     var n = dl
+ 
+     var srt = function(a, b) {
+         if (a.name < b.name)
+             return -1
+         if (a.name > b.name)
+             return 1
+         return 0
+     }
+ 
+     db.sort(srt)
+     do {
+         var i = dl - n
+         if (n == 1) {
+             rdb.push(db[i])
+         } else if (db[i].name != db[i + 1].name) {
+             rdb.push(db[i])
+         }
+     } while (--n)
+     return rdb
+ }
+ 
+ function dbFilter(db, restrict) {
+     var rdb = []
+     var dl = db.length
+     if (dl < 1) {
+         return db
+     }
+     if (typeof(restrict) == 'string')
+         restrict = [restrict]
+     for (var i = 0; i < restrict.length; i++) {
+         var n = dl
+         var r = restrict[i]
+         do {
+             if (db[dl - n].type == r) {
+                 rdb.push(db[dl - n])
+             }
+         } while (--n)
+     }
+     return rdb
+ }
+ 
diff -c -r -N minion.orig//chrome/content/mpmCommon.js minion.patched//chrome/content/mpmCommon.js
*** minion.orig//chrome/content/mpmCommon.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/mpmCommon.js	2012-03-30 22:50:35.025112749 +0200
***************
*** 0 ****
--- 1,26 ----
+ var EXPORTED_SYMBOLS = [ "nsMPM" ];
+ 
+ /**
+  * nsMPM namespace.
+  */
+ var nsMPM = {
+ 	Cc: Components.classes,
+ 	Ci: Components.interfaces,
+ 	Cu: Components.utils,
+ 	JSON: null,
+ 	FileIO: null,
+ 	DirIO: null,
+ 	mpmMenu: null,
+ 	mpd: null,
+ 	mpmUpgrade: null,
+ 	
+ 	pref_dir: "ProfD", // http://mxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h
+ 	pref_file_servers: "mpm_servers.js",
+ 	pref_file_menus: "mpm_menus.js",
+ 	
+ 	instance_count: 0
+ };
+ 
+ // independent js modules
+ if (!nsMPM.JSON) Components.utils.import("chrome://minion/content/JSON.js",nsMPM);
+ if (!nsMPM.FileIO)Components.utils.import("chrome://minion/content/io.js",nsMPM);
diff -c -r -N minion.orig//chrome/content/mpmMenu.js minion.patched//chrome/content/mpmMenu.js
*** minion.orig//chrome/content/mpmMenu.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/mpmMenu.js	2012-03-30 22:52:02.433108500 +0200
***************
*** 0 ****
--- 1,293 ----
+ Components.utils.import("chrome://minion/content/mpmUtils.js");
+ 
+ let EXPORTED_SYMBOLS = ["mpmMenu"]
+ 
+ var mpmMenu = {
+ 	items: [],
+ 	_loadDefaults : function () {
+ 		this.items = [
+ 			{
+ 				id : "mpm_menu_toggle_cs",
+ 				label : nsMPM.translateService.GetStringFromName("toggle_song_display"),
+ 				locations : "statusbar",
+ 				targets : null,
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "nsMPM.prefs.set (\n    'sb_currentsong_hide',\n    !nsMPM.prefs.get('sb_currentsong_hide')\n);"
+ 			}, {
+ 				id : "mpm_menu_add",
+ 				label : nsMPM.translateService.GetStringFromName("add_to_playlist"),
+ 				locations : "mpdbrowser",
+ 				targets : "file directory Artist Album Date Genre Performer Composer",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "mpdbrowser.addSelected()"
+ 			}, {
+ 				id : "mpm_menu_replace",
+ 				label : nsMPM.translateService.GetStringFromName("replace_playlist"),
+ 				locations : "mpdbrowser",
+ 				targets : "file directory Artist Album Date Genre Performer Composer",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : "clear",
+ 				script : "mpdbrowser.addSelected()"
+ 			}, {
+ 				id : "mpm_menu_viewDetails",
+ 				label : nsMPM.translateService.GetStringFromName("view_song_details"),
+ 				locations : null,
+ 				targets : "file",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "mpdbrowser.showDetails(item)"
+ 			}, {
+ 				id : "mpm_menu_setFileAction",
+ 				label : nsMPM.translateService.GetStringFromName("set_default_action"),
+ 				locations : "mpdbrowser",
+ 				targets : "file",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "nsMPM.mpm_openDialog('chrome://minion/content/fileActions.xul', 'mpm_file_actions')"
+ 			}, {
+ 				id : "mpm_menu_update",
+ 				label : nsMPM.translateService.GetStringFromName("update_this_folder"),
+ 				locations : null,
+ 				targets : "directory",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "mpdbrowser.doUpdate()"
+ 			}, "separator", {
+ 				id : "mpm_menu_loadPlaylist",
+ 				label : nsMPM.translateService.GetStringFromName("load_playlist"),
+ 				locations : "mpdbrowser",
+ 				targets : "playlist",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : "clear; load {Title}",
+ 				script : null
+ 			}, {
+ 				id : "mpm_custom_playlistAppend",
+ 				label : nsMPM.translateService.GetStringFromName("append_playlist"),
+ 				locations : "mpdbrowser",
+ 				targets : "playlist",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : "load {Title}",
+ 				script : null
+ 			}, {
+ 				id : "mpm_menu_rmPlaylist",
+ 				label : nsMPM.translateService.GetStringFromName("delete_playlist"),
+ 				locations : "mpdbrowser",
+ 				targets : "playlist",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : "rm {Title}",
+ 				script : null
+ 			}, {
+ 				id : "mpm_menu_renPlaylist",
+ 				label : nsMPM.translateService.GetStringFromName("rename_playlist"),
+ 				locations : "mpdbrowser",
+ 				targets : "playlist",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "var name = prompt(\""+nsMPM.translateService.GetStringFromName("enter_new_name")+"\", item.Title);\nif (name) nsMPM.mpd.doCmd(\"rename \"+nsMPM.Sz(item.Title)+\" \"+nsMPM.Sz(name))"
+ 			}, "separator", {
+ 				id : "mpm_menu_playlistRemove",
+ 				label : nsMPM.translateService.GetStringFromName("remove_from_playlist"),
+ 				locations : "mpdplaylist",
+ 				targets : "file",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "mpdplaylist.delete()"
+ 			}, {
+ 				id : "mpm_menu_playlistmvFirst",
+ 				label : nsMPM.translateService.GetStringFromName("move_to_begining_playlist"),
+ 				locations : "mpdplaylist",
+ 				targets : "file",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "mpdplaylist.moveFirst()"
+ 			}, {
+ 				id : "mpm_menu_playlistmvNext",
+ 				label : nsMPM.translateService.GetStringFromName("move_to_next_in_queue"),
+ 				locations : "mpdplaylist",
+ 				targets : "file",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "mpdplaylist.moveNext()"
+ 			}, {
+ 				id : "mpm_menu_playlistmvLast",
+ 				label : nsMPM.translateService.GetStringFromName("move_to_end_playlist"),
+ 				locations : "mpdplaylist",
+ 				targets : "file",
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "mpdplaylist.moveLast()"
+ 			}, {
+ 				id : "mpm_menu_ClearPlaylist",
+ 				label : nsMPM.translateService.GetStringFromName("clear_playlist"),
+ 				locations : "mpdplaylist",
+ 				targets : null,
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : "clear",
+ 				script : null
+ 			}, {
+ 				id : "mpm_menu_SavePlaylist",
+ 				label : nsMPM.translateService.GetStringFromName("save_playlist_as"),
+ 				locations : "mpdplaylist",
+ 				targets : null,
+ 				URL : null,
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : "var name = prompt('"+nsMPM.translateService.GetStringFromName("enter_playlist_name")+"');\n"+
+ 					"nsMPM.mpd.doCmd('save \"' + name.replace(/\"/g, '\\\"') + '\"')"
+ 			}, "separator", {
+ 				id : "mpm_menu_google",
+ 				label : nsMPM.translateService.GetStringFromName("google_it"),
+ 				locations : null,
+ 				targets : "file Artist Album",
+ 				URL : "http://www.google.com/search?q={Artist}+{Title}",
+ 				queryType : null,
+ 				queryScope : null,
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : null
+ 			}, {
+ 				id : "mpm_menu_viewAlbum",
+ 				label : nsMPM.translateService.GetStringFromName("view_this_album"),
+ 				locations : null,
+ 				targets : "file",
+ 				URL : null,
+ 				queryType : "file",
+ 				queryScope : "Album",
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : null
+ 			}, {
+ 				id : "mpm_menu_viewArtistAlbum",
+ 				label : nsMPM.translateService.GetStringFromName("view_albums_by_artist"),
+ 				locations : null,
+ 				targets : "file Artist",
+ 				URL : null,
+ 				queryType : "Album",
+ 				queryScope : "Artist",
+ 				filterField: null,
+ 				mpdCommand : null,
+ 				script : null
+ 			}
+ 		]
+ 	},
+ 	/* "locations" and "targets":
+ 	 * Determines when menuitem is shown.  
+ 	 * "locations" matches tag names:
+ 	 *      mpdbrowser, mpdplaylist, currentsong, etc.
+ 	 * "targets" matches type of item clicked on:
+ 	 *      file, Artist, Album, playlist, etc.
+ 	 * Null values matches any.
+ 	 * 
+ 	 * "URL", "query*", "mpdCommand":
+ 	 * Place item and mpd values in {} to have them replaced
+ 	 * at runtime.  URL loads web pages, queries lookup in the
+ 	 * database and displays results, mpdCommand uses the MPD protocol.
+ 	 * Use ; to seperate multiple commands in mpdCommand.
+ 	 * i.e.: mpdCommand = "add {file};play {playlistlength}"
+ 	 * 
+ 	 * "script" will be evaluated at runtime.
+ 	 */
+ 	mpmMenuItem : function (label, id) {
+ 		var newItem = {};
+ 		
+ 		newItem.id = nsMPM.Nz(id, "mpm_custom_menuItem")
+ 		newItem.label = nsMPM.Nz(label, nsMPM.translateService.GetStringFromName("new_menu_item"))
+ 		
+ 		newItem.locations = null
+ 		newItem.targets = null
+ 		
+ 		newItem.URL = null
+ 		newItem.queryType = null
+ 		newItem.queryScope = null
+ 		newItem.filterField = null
+ 		newItem.mpdCommand = null
+ 		newItem.script = null
+ 		return newItem;
+ 	},
+ 	_loadMenuItems : function () {
+ 		try {
+ 			let that = this;
+ 			var file = nsMPM.DirIO.get(nsMPM.pref_dir);
+ 			file.append(nsMPM.pref_file_menus);
+ 			if (file.exists()) {
+ 				nsMPM.debug("Read menus from "+file.path);
+ 				var str = nsMPM.FileIO.read(file);
+ 				that.items = nsMPM.JSON.parse(str);
+ 			} else {
+ 				nsMPM.debug("Creating default menus.")
+ 				this._loadDefaults();
+ 				this._saveMenuItems();
+ 			}
+ 			file = null;
+ 		} catch(e){dump(e+"\n"); dump(this+"\n")}
+ 	},
+ 	_saveMenuItems : function() {
+ 		let that = this;
+ 		var file = nsMPM.DirIO.get(nsMPM.pref_dir);
+ 		file.append(nsMPM.pref_file_menus);
+ 		nsMPM.debug("Saving menus to :"+file.path);
+ 		if (!file.exists()) {
+ 			nsMPM.FileIO.create(file);
+ 		}
+ 		var str = nsMPM.JSON.stringify(that.items);
+ 		nsMPM.FileIO.write(file, str);
+ 		file = null;
+ 	},
+ 	
+ 	load: function() { this._loadMenuItems(); },
+ 	restore: function () { this._loadDefaults(); this._saveMenuItems() },
+ 	save: function() { this._saveMenuItems(); }
+ }
+ 
+ 
+ 
+ 
diff -c -r -N minion.orig//chrome/content/mpmUpgrade.js minion.patched//chrome/content/mpmUpgrade.js
*** minion.orig//chrome/content/mpmUpgrade.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/mpmUpgrade.js	2012-03-30 22:55:26.281098592 +0200
***************
*** 0 ****
--- 1,251 ----
+ Components.utils.import("chrome://minion/content/mpmUtils.js");
+ 
+ let EXPORTED_SYMBOLS = ["mpmUpgrade"]
+ 
+ // Old variables. Now discarder. see mpmCommon.js.
+ var pref_dir_old = "Home";
+ var pref_file_menus_old = ".mpm_menus.js";
+ var pref_file_servers_old = ".mpm_servers.js";
+ var pref_file_state_old = ".mpm_browser_state.js";
+ 
+ var mpmUpgrade = {};
+ 
+ function mpmUpgrade206(mpd) {
+ 	try {
+ 		if ( nsMPM.prefs.isPref('use_amazon_art') ) {
+ 			if (typeof(nsMPM.prefs.get("use_amazon_art",1)) == "boolean" ) nsMPM.prefs.clear("use_amazon_art");
+ 		}
+ 
+ 		// it is not possible to restore old menus stored in JS and get them converted to JSON
+ 		// So, we have to restore defaults value.
+ 		// This concerns only "beta" user of 2.0.x branch
+ 		var file = nsMPM.DirIO.get(pref_dir_old);
+ 		file.append(pref_file_menus_old);
+ 		if (file.exists()) {
+ 			nsMPM.FileIO.unlink(file);
+ 		}
+ 		nsMPM.mpmMenu.restore(); // Will overwrite any already migrated menus
+ 
+ 		nsMPM.debug('Upgrade for 2.0.6: Ok');
+ 	} catch(e) {
+ 		nsMPM.debug('Upgrade for 2.0.6: Failed');
+ 		nsMPM.debug(e);
+ 	}
+ 	return true;
+ }
+ 
+ function mpmUpgrade204(mpd) {
+ 	try {
+ 		if ( nsMPM.prefs.isPref('persistant_state') ) nsMPM.prefs.clear("persistant_state");
+ 
+ 		var file = nsMPM.DirIO.get(pref_dir_old);
+ 		file.append(pref_file_state_old);
+ 		if (file.exists()) nsMPM.FileIO.unlink(file);
+ 
+ 		nsMPM.debug('Upgrade for 2.0.4: Ok');
+ 	} catch(e) {
+ 		nsMPM.debug('Upgrade for 2.0.4: Failed');
+ 		nsMPM.debug(e);
+ 	}
+ 	return true;
+ }
+ 
+ function mpmUpgrade200(mpd) {
+ 	try {
+ 		var file = nsMPM.DirIO.get(pref_dir_old);
+ 		file.append(pref_file_servers_old);
+ 		if (file.exists()) {
+ 			nsMPM.debug('Upgrading old server nsMPM.prefs');
+ 			var str = nsMPM.FileIO.read(file);
+ 			nsMPM.mpd.servers = nsMPM.JSON.parse(str);
+ 			nsMPM.FileIO.unlink(file);
+ 			nsMPM.mpd.setServers(nsMPM.mpd.servers);
+ 		}
+ 		nsMPM.debug('Upgrade for 2.0.0: Ok');
+ 	} catch(e) {
+ 		nsMPM.debug('Upgrade for 2.0.0: Failed');
+ 		nsMPM.debug(e);
+ 	}
+ 	return true;
+ }
+ 
+ function mpmUpgrade144(mpd) {
+ 	try {
+ 		var host = nsMPM.prefs.get('mpd_host');
+ 		var port = nsMPM.prefs.get('mpd_port');
+ 		var password = nsMPM.prefs.get('mpd_password');
+ 
+ 		nsMPM.prefs.set('server',host+':'+port+':'+password);
+ 
+ 		var servers = [];
+ 		var server = [];
+ 		server.push('MPD server');
+ 		server.push(host+':'+port+':'+password);
+ 		servers.push(server);
+ 		
+ 		nsMPM.mpd.setServers(servers);
+ 
+ 		nsMPM.prefs.clear("mpd_host");
+ 		nsMPM.prefs.clear("mpd_port");
+ 		nsMPM.prefs.clear("mpd_password");
+ 		nsMPM.prefs.clear("playlist_mode");
+ 		nsMPM.prefs.clear("home");
+ 
+ 		nsMPM.debug('Upgrade for 1.4.4: Ok');		
+ 	} catch(e) {
+ 		nsMPM.debug('Upgrade for 1.4.4: Failed');
+ 		nsMPM.debug(e);
+ 	}
+ 	return true;
+ }
+ 
+ function mpmCleanOldPrefs() {
+ 	oldPrefs = ["mpd_host", "mpd_port", "mpd_password", "playlist_mode", "home", "use_amazon_art", "persistant_state"];
+ 	for(i=0; i<oldPrefs.length; i++){
+ 		if ( nsMPM.prefs.isPref(oldPrefs[i]) ) nsMPM.prefs.clear(oldPrefs[i]);
+ 	}
+ }
+ 
+ function mpmGetPreviousVersion() {
+ 	if ( nsMPM.prefs.isPref('version') ) return nsMPM.prefs.get('version');
+ 
+ 	if ( nsMPM.prefs.isPref('save_art_url') ) return '2.0.8';
+ 	
+ 	var menus_file = nsMPM.DirIO.get(nsMPM.pref_dir);
+ 	menus_file.append(nsMPM.pref_file_menus);
+ 	var servers_file = nsMPM.DirIO.get(nsMPM.pref_dir);
+ 	servers_file.append(nsMPM.pref_file_servers);
+ 	if ( servers_file.exists() && menus_file.exists() ) return '2.0.6';
+ 
+ 	if ( nsMPM.prefs.isPref('nsMPM.debug') ) return '2.0.4';
+ 
+ 	menus_file = nsMPM.DirIO.get(pref_dir_old);
+ 	menus_file.append(pref_file_menus_old);
+ 	servers_file = nsMPM.DirIO.get(pref_dir_old);
+ 	servers_file.append(pref_file_servers_old);
+ 	if ( servers_file.exists() || menus_file.exists() ) return '2.0.0';
+ 
+ 	if ( nsMPM.prefs.isPref('mpd_host') ) return '1.4.4';
+ 	return mpmGetCurrentVersion();
+ }
+ 
+ function mpmGetCurrentVersion() {
+ 	var rdfs = Components.classes['@mozilla.org/rdf/rdf-service;1']
+ 				.getService(Components.interfaces.nsIRDFService);
+ 	var extension = rdfs.GetResource('urn:mozilla:item:Music_Player_Minion@code.google.com');
+ 	var gExtensionDB = Components.classes['@mozilla.org/extensions/manager;1']
+ 				.getService(Components.interfaces.nsIExtensionManager)
+ 				.QueryInterface(Components.interfaces.nsIExtensionManager)
+ 				.datasource;
+ 
+ 	// Version
+ 	var versionArc = rdfs.GetResource(EM_NS('version'));
+ 	var version = gExtensionDB.GetTarget(extension, versionArc, true);
+ 	return version.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+ }
+ 
+ function mpmSetUpgraded(isUpgraded) {
+ 	if ( typeof(isUpgraded) == 'boolean' ) nsMPM.prefs.set('upgraded',isUpgraded);
+ 	else nsMPM.prefs.set('upgraded',false);
+ }
+ 
+ function EM_NS(aProperty) {
+     return 'http://www.mozilla.org/2004/em-rdf#' + aProperty;
+ }
+ 
+ function mpmSetCurrentVersion() {
+ 	nsMPM.prefs.set('version',mpmGetCurrentVersion());
+ }
+ 
+ // Upgrade dialog box functions
+ mpmUpgrade.check = function(mpd) {
+ 	try {
+ 		var oldVersion = mpmGetPreviousVersion();
+ 		if ( oldVersion == mpmGetCurrentVersion() ) {
+ 			nsMPM.debug('No upgrades to do');
+ 			return;
+ 		}
+ 
+ 		nsMPM.debug('mpm preferences need to be upgraded ('+mpmGetPreviousVersion()+' != '+mpmGetCurrentVersion()+')');
+ 		switch(oldVersion) {
+ 			case '1.4.4':
+ 				mpmSetUpgraded(mpmUpgrade144(mpd));
+ 			break;
+ 			case '2.0.0':
+ 				mpmSetUpgraded(mpmUpgrade200(mpd));
+ 			case '2.0.4':
+ 				mpmSetUpgraded(mpmUpgrade204(mpd));
+ 			case '2.0.6':
+ 				mpmSetUpgraded(mpmUpgrade206(mpd));
+ 			case '2.0.12':
+ 				mpmSetUpgraded(true);
+ 			break;
+ 			default:
+ 				nsMPM.debug('This version has nothing to upgrade ('+oldVersion+')');
+ 				mpmSetUpgraded(true);
+ 			break;
+ 		}
+ 		mpmCleanOldPrefs();
+ 		mpmSetCurrentVersion();
+ 		nsMPM.debug('Upgrade done');
+ 	} catch(e) { nsMPM.debug(e); }
+ }
+ 
+ mpmUpgrade.isUpgraded = function(reset) {
+ 	var isUpgraded = nsMPM.prefs.get('upgraded',true);
+ 	if ( typeof(reset) == 'boolean' && reset == true ) 	nsMPM.prefs.set('upgraded',false);
+ 	return isUpgraded;
+ }
+ 
+ mpmUpgrade.dialogInit = function(document){
+ 	try {
+ 		var rdfs = Components.classes['@mozilla.org/rdf/rdf-service;1'].
+ 							  getService(Components.interfaces.nsIRDFService);
+ 		var extension = rdfs.GetResource('urn:mozilla:item:Music_Player_Minion@code.google.com');
+ 		var gExtensionDB = Components.classes['@mozilla.org/extensions/manager;1'].
+ 						   getService(Components.interfaces.nsIExtensionManager).
+ 						   QueryInterface(Components.interfaces.nsIExtensionManager).
+ 						   datasource;
+ 	
+ 		var extensionsStrings = document.getElementById('extensionsStrings');
+ 	
+ 		// Name
+ 		var nameArc = rdfs.GetResource(EM_NS('name'));
+ 		var name = gExtensionDB.GetTarget(extension, nameArc, true);
+ 		name = name.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+ 	
+ 		// Version
+ 		version = mpmGetCurrentVersion();
+ 	
+ 		// Description
+ 		var descriptionArc = rdfs.GetResource(EM_NS('description'));
+ 		var description = gExtensionDB.GetTarget(extension, descriptionArc, true);
+ 		if (description)
+ 		  description = description.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+ 	
+ 		document.title = extensionsStrings.getFormattedString('aboutWindowTitle', [name]);
+ 		var extensionName = document.getElementById('extensionName');
+ 		extensionName.setAttribute('value', name);
+ 		var extensionVersion = document.getElementById('extensionVersion');
+ 		extensionVersion.setAttribute('value', version);
+ 	
+ 		var extensionDescription = document.getElementById('extensionDescription');
+ 		extensionDescription.appendChild(document.createTextNode(description));
+ 	
+ 		var acceptButton = document.documentElement.getButton('accept');
+ 		acceptButton.label = extensionsStrings.getString('aboutWindowCloseButton');
+ 		nsMPM.debug('fin init');
+ 	} catch(e){nsMPM.debug(e);}
+ }
+ 
+ mpmUpgrade.doServer = function() {
+ 	nsMPM.mpm_openDialog('chrome://minion/content/servers.xul', 'servers');
+ }
+ 
+ mpmUpgrade.doSettings = function() {
+ 	nsMPM.mpm_openDialog('chrome://minion/content/settings.xul', 'settings');
+ }
+ 
+ mpmUpgrade.doAbout = function() {
+ 	nsMPM.mpm_openDialog('chrome://minion/content/about/about.xul', 'about');
+ }	
\ No newline at end of file
diff -c -r -N minion.orig//chrome/content/mpmUtils.js minion.patched//chrome/content/mpmUtils.js
*** minion.orig//chrome/content/mpmUtils.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/mpmUtils.js	2012-03-30 22:51:43.477109421 +0200
***************
*** 0 ****
--- 1,1246 ----
+ /**
+  * Music Player Minion Copyright 2008, Chris Seickel
+  *
+  * This program is free software; you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free Software
+  * Foundation; either version 2 of the License, or (at your option) any later
+  * version.
+  *
+  * This program is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+  * details.
+  *
+  * You should have received a copy of the GNU General Public License along with
+  * this program; if not, write to the Free Software Foundation, Inc., 51
+  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ var EXPORTED_SYMBOLS = ["nsMPM"];
+ 
+ Components.utils.import("chrome://minion/content/mpmCommon.js");
+ 
+ nsMPM.observerService  = nsMPM.Cc["@mozilla.org/observer-service;1"]
+ 						.getService(nsMPM.Ci.nsIObserverService);
+ nsMPM.consoleService   = nsMPM.Cc["@mozilla.org/consoleservice;1"]
+ 						.getService(nsMPM.Ci.nsIConsoleService);
+ nsMPM.winw 			   = nsMPM.Cc["@mozilla.org/embedcomp/window-watcher;1"]
+ 						.getService(nsMPM.Ci.nsIWindowWatcher);
+ nsMPM.slidetimer 	   = nsMPM.Cc["@mozilla.org/timer;1"]
+ 						.createInstance(nsMPM.Ci.nsITimer);
+ nsMPM.translateService = nsMPM.Cc["@mozilla.org/intl/stringbundle;1"]
+ 						.getService(nsMPM.Ci.nsIStringBundleService)
+ 						.createBundle("chrome://minion/locale/strings.properties");
+ nsMPM.env =				nsMPM.Cc["@mozilla.org/process/environment;1"].
+ 						getService(nsMPM.Ci.nsIEnvironment);
+ 
+ nsMPM.getStringTime = function() {
+ 	var today = new Date();
+ 	var strDate = "";
+ 	var t = 0;
+ 	
+ 	t = today.getHours();
+ 	if ( t.toString().length == 1 ) strDate += '0';
+ 	strDate += t +':';
+ 	
+ 	t = today.getMinutes();
+ 	if ( t.toString().length == 1 ) strDate += '0';
+ 	strDate += t +':';
+ 
+ 	t = today.getSeconds();
+ 	if ( t.toString().length == 1 ) strDate += '0';
+ 	strDate += t +'.';
+ 	
+ 	t = today.getMilliseconds();
+ 	if ( t.toString().length == 1 ) strDate += '00';
+ 	if ( t.toString().length == 2 ) strDate += '0';
+ 	strDate += t;
+ 	
+ 	return strDate;
+ }
+ 
+ nsMPM.debug = function (s) {
+ 	let that = this;
+ 	
+ 	if ( typeof(that) == 'undefined' ) dump("that doesn't exists\n");
+ 	if ( typeof(that.prefs) == 'undefined' ) dump("that.prefs doesn't exists\n");
+ 	
+ 	if ( that.prefs.get("debug", false) != true ) return;	
+ 	try {
+ 		var strDate = that.getStringTime();
+ 		var f = 0;
+ 		var str = "";
+ 		if (s == null) s = "null passed to debug";
+ 		if (typeof(s) == 'object') {
+ 			for (x in s) {
+ 				try {
+ 					if ( f != 0 ) str += "\n             ";
+ 					str += x + ': ' + s[x];
+ 				} catch (e) {
+ 					if ( f != 0 ) str += "\n             ";
+ 					str += x + ': ERROR';
+ 				}
+ 				f=1;
+ 			}
+ 		} else if (typeof(str) == 'string') {
+ 			var str = s;
+ 		}
+ 		if (typeof(str) == 'string' && str.length > 0) {
+ 			dump(strDate + ' ' + str + "\n");
+ 			//that.consoleService.logStringMessage(str)
+ 		}
+ 	} catch (e) {
+ 		dump("error in debug!")
+ 		dump(e);
+ 		that.consoleService.logStringMessage("error in debug!")
+ 	}
+ }
+ 
+ nsMPM.Nz = function(obj, def) {
+ 	if (typeof(obj) == 'undefined') {
+ 		return (typeof(def) == 'undefined') ? null : def
+ 	}
+ 	return obj
+ }
+ 
+ nsMPM.Sz = function(str) {
+     /* Prepare strings for mpd socket communications */
+     if (typeof(str) == "string")
+         return '"' + str.replace(/\"/g, '\\"') + '"'
+     return "''"
+ }
+ 
+ nsMPM.smartsort = function(a,b) {
+     if (a.type != b.type) {
+         if (a.type>b.type) return 1
+         if (a.type<b.type) return -1
+     }
+     var column = "name"     
+     if (isNaN(a[column]+b[column])) {
+         var al = a[column].toLowerCase()
+         var bl = b[column].toLowerCase()
+         if (al>bl) return 1
+         if (al<bl) return -1
+         return 0
+     }
+     else { return a[column]-b[column]}
+ }
+ 
+ nsMPM.urlReplace = function(s, item) {   
+ 	let that = this;
+ 
+ 	if (that.Nz(item.file)) item.Path = item.file.split("/").slice(0,-1).join("/");
+ 	// that.debug(item);
+ 	for (x in item) {
+ 		var re = new RegExp("{"+x+"}","ig");
+ 		s = s.replace(re, that.fixedEncodeURI(item[x]));
+ 	}
+ 	s = s.replace(/{[^}]+}/g,"");
+ 	return s;
+ }
+ 
+ nsMPM.fixedEncodeURI = function(str) {
+ 	// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/encodeURIComponent
+ 	// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/encodeURI
+ 	return encodeURI(str).replace(/!/g, '%21').replace(/'/g, '%27')
+ 							  .replace(/\(/g, '%28').replace(/\)/g, '%29')
+ 							  .replace(/\*/g, '%2A').replace(/\@/g, '%40')
+ 							  .replace(/&/g, '%26').replace(/#/g, '%23');
+ }
+ 
+ nsMPM.getFileContents = function(aURL) {
+ 	let that = this;
+ 	var ioService = that.Cc["@mozilla.org/network/io-service;1"].getService(that.Ci.nsIIOService);
+ 	var scriptableStream = that.Cc["@mozilla.org/scriptableinputstream;1"].getService(that.Ci.nsIScriptableInputStream);
+ 
+ 	var channel = ioService.newChannel(aURL, null, null);
+ 	var input = channel.open();
+ 	scriptableStream.init(input);
+ 	var str = scriptableStream.read(input.available());
+ 	scriptableStream.close();
+ 	input.close();
+ 	return str;
+ }
+ 
+ nsMPM.hmsFromSec = function(sec) {
+ 	var hms = "0:00";
+ 	try {
+ 		sec = parseInt(sec);
+ 	} catch (err) {
+ 		return "0:00";
+ 	}
+ 	if (sec > 0) {
+ 		var h = 0;
+ 		if (sec >= 3600) {
+ 			h = Math.floor(sec / 3600);
+ 			sec = sec % 3600;
+ 		}
+ 		var m = Math.floor(sec / 60);
+ 		var s = sec % 60;
+ 		if (h > 0) {
+ 			h = h + ":";
+ 			if (m.toString().length == 1) m = "0" + m;
+ 		} else h = "";
+ 
+ 		m = m + ":";
+ 		if (s.toString().length == 1) s = "0" + s;
+ 		hms = h + m + s;
+ 	}
+ 	return hms;
+ }
+ 
+ nsMPM.prettyTime = function(sec, round) {
+ 	let that = this;
+ 	var tm = ""
+ 	try {
+ 		sec = parseInt(sec)
+ 	} catch (err) {
+ 		that.debug("prettyTime: " + err.description);
+ 		sec = 0
+ 	}
+ 	if (sec > 0) {
+ 		var d = Math.floor(sec / 86400)
+ 		sec = sec % 86400
+ 		var h = Math.floor(sec / 3600)
+ 		sec = sec % 3600
+ 		var m = Math.floor(sec / 60)
+ 		var s = sec % 60
+ 		var sep = ""
+ 
+ 		if (d > 0) {
+ 			if (d > 1) tm = d + " " + that.translateService.GetStringFromName("days");
+ 			else tm = d + " " + that.translateService.GetStringFromName("day");
+ 			sep = ", ";
+ 		}
+ 
+ 		if (h > 0) {
+ 			tm += sep;
+ 			if ( h > 1 ) {
+ 				if (d > 0) tm += h + " " + that.translateService.GetStringFromName("hrs");
+ 				else tm += h + " " + that.translateService.GetStringFromName("hours");
+ 			} else {
+ 				if (d > 0) tm += h + " " + that.translateService.GetStringFromName("hr");
+ 				else tm += h + " " + that.translateService.GetStringFromName("hour");
+ 			}
+ 			sep = ", ";
+ 		}
+ 
+ 		if (m > 0) {
+ 			tm += sep;
+ 			if ( m > 1 ) {
+ 				if (d > 0) tm += m + " " + that.translateService.GetStringFromName("mins");
+ 				else tm += m + " " + that.translateService.GetStringFromName("minutes");
+ 			} else {
+ 				if (d > 0) tm += m + " " + that.translateService.GetStringFromName("min");
+ 				else tm += m + " " + that.translateService.GetStringFromName("minute");
+ 			}
+ 			sep = ", ";
+ 		}
+ 
+ 		if (!that.Nz(round) && s > 0) {
+ 			tm += sep;
+ 			if ( s > 1 ) {
+ 			if (d > 0) tm += s + " " + that.translateService.GetStringFromName("secs");
+ 			else tm += s + " " + that.translateService.GetStringFromName("seconds");
+ 			} else {
+ 				if (d > 0) tm += s + " " + that.translateService.GetStringFromName("sec");
+ 				else tm += s + " " + that.translateService.GetStringFromName("second");
+ 			}
+ 		}
+ 	}
+ 	return tm
+ }
+ 
+ nsMPM.copyArray = function(oldArray) {
+ 	if (typeof(oldArray) == 'object') {
+ 		var l = oldArray.length
+ 		var n = l
+ 		var newArray = []
+ 		if (l > 0) {
+ 			do {
+ 				newArray.push(oldArray[l - n])
+ 			} while (--n)
+ 		}
+ 		return newArray
+ 	} else
+ 		return oldArray
+ }
+ 
+ nsMPM.getAmazonArt = function(mpd, item, img) {
+ 	let that = this;
+ 	
+ 	var art = "chrome://minion/content/images/album_blank.png";
+ 	var search_url = that.urlReplace(
+ 					"http://musicbrainz.org/ws/1/release/?type=xml&artist={Artist}&title={Album}&limit=1",
+ 					item);
+ 	if ( typeof(item.Album) != 'string' || typeof(item.Artist) != 'string' 
+ 			|| item.Album == "" || item.Artist == "") {
+ 		that.debug("Not enough info for search...")
+ 		img.src = 'chrome://minion/content/images/album_blank_no_info.png';
+ 		img.setAttribute("tooltiptext",that.translateService.GetStringFromName("track_no_info"));	
+ 	} else {
+ 		that.debug("searching Metabrainz...")
+ 		if (typeof(nsMPM.mpd.cachedArt[search_url]) == 'string') {
+ 			img.src = nsMPM.mpd.cachedArt[search_url];
+ 			img.setAttribute("tooltiptext",nsMPM.mpd.cachedArt[search_url]);
+ 		} else {
+ 			var cb = function(data) {
+ 				try {
+ 					var asin = "";
+ 					if (data != "") {
+ 						var s = data.indexOf("<asin>") + 6;
+ 						if (s > 6) {
+ 							var e = data.indexOf("</asin>", s);
+ 							if (e > 0) {
+ 								asin = data.slice(s, e);
+ 							}
+ 							if (asin.length == 10 && asin != '          ') {
+ 								base = "http://images.amazon.com/images/P/" + asin;
+ 								art = base + ".01.MZZZZZZZ.jpg";
+ 							}
+ 						}
+ 					}
+ 					that.debug('applying art='+art);
+ 					nsMPM.mpd.cachedArt[search_url] = art;
+ 					img.src = art;
+ 					img.setAttribute("tooltiptext",art);
+ 					that.SaveImageToURL(item,art);
+ 				} catch (e) {
+ 					that.debug(e);
+ 				}
+ 			};
+ 			that.fetch(search_url, cb);
+ 		}
+ 	}
+ }
+ 
+ nsMPM.SaveImageToURL = function(item,url) {
+ 	let that = this;
+ 	
+ 	try {
+ 		that.debug('SaveImageToURL url=');
+ 		that.debug(url);
+ 		// we want to reject dummy requests
+ 		var txt = new String(url);
+ 		if (txt.indexOf('chrome://') == 0) return;
+ 
+ 		// unless specified, we don't save arts
+ 		if ( parseInt(that.prefs.get("use_amazon_art",1)) != 2 ) {
+ 			return;
+ 		}
+ 		
+ 		// the source object we want to download
+ 		var oSourceURL = that.Cc["@mozilla.org/network/io-service;1"]
+ 			.getService(that.Ci.nsIIOService)
+ 			.newURI(url, null, null);
+ 		
+ 		// if file:// we want to probe if it already exists
+ 		var oTargetFile = that.Cc["@mozilla.org/file/local;1"]
+ 			.createInstance(that.Ci.nsILocalFile);
+ 		// use to create the destination object
+ 		var ioService = that.Cc["@mozilla.org/network/io-service;1"]
+ 			.getService(that.Ci.nsIIOService);
+ 		
+ 		var sTargetFile = that.urlReplace(that.prefs.get("save_art_url"), item);
+ 		var oDestination = ioService.newURI(sTargetFile,null,null);
+ 
+ 		that.debug("Attempt to download url: "+url);
+ 		that.debug("Attempt to save to file: "+sTargetFile);
+ 
+ 		// Probe if the file already exists
+ 		if ( oDestination.scheme == 'file://' ) {		
+ 			oTargetFile.initWithPath(oDestination.path);		
+ 			if(oTargetFile.exists()) {
+ 				that.debug("File already exists");
+ 				return;
+ 			} else {
+ 				oTargetFile.create(0x00,0640);
+ 			}
+ 		}
+ 
+ 		// create a persist
+ 		var persist = that.Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
+ 			createInstance(that.Ci.nsIWebBrowserPersist);
+ 
+ 		// with persist flags if desired See nsIWebBrowserPersist page for more PERSIST_FLAGS.
+ 		const nsIWBP = that.Ci.nsIWebBrowserPersist;
+ 		// const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
+ 		const flags = nsIWBP.PERSIST_FLAGS_NONE;
+ 		persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_FROM_CACHE;
+ 
+ 		// do the save
+ 		persist.saveURI(oSourceURL, null, null, null, null, oDestination);
+ 
+ 	} catch(e) { 
+ 		that.debug(e); 
+ 	}
+ }
+ 
+ nsMPM.prefetchImageFromURL = function(url, callBack, arg) {
+ 	let that = this;
+ 	try {
+ 		that.debug('Prefetch requested');
+ 		var imgRequest = that.Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+ 						.createInstance();
+ 		imgRequest.QueryInterface(that.Ci.nsIDOMEventTarget);
+ 		imgRequest.QueryInterface(that.Ci.nsIXMLHttpRequest);
+ 
+ 		imgRequest.open("POST", url, true);
+ 		imgRequest.onreadystatechange = function() {
+ 			if (imgRequest.readyState == 4) {
+ 				imgRequest.onreadystatechange = null;
+ 				var status = imgRequest.status;
+ 				imgRequest = null;
+ 				callBack(status, arg, url);
+ 			}
+ 		};
+ 		imgRequest.send("q="+(Math.random()*10000));
+ 	} catch (e) { 
+ 		// exception was raised, so we fallback to amazon if possible
+ 		// that.debug(e);
+ 		callBack(404, arg, url);
+ 	}
+ }
+ 
+ nsMPM.fetch = function(url, callBack, arg, getXML) {
+ 	let that = this;
+ 	try {
+ 		var request = that.Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
+ 		request.QueryInterface(that.Ci.nsIDOMEventTarget);
+ 		request.QueryInterface(that.Ci.nsIXMLHttpRequest);
+ 
+ 		request.open("GET", url, true)
+ 		request.onreadystatechange = function() {
+ 			try{
+ 				that.debug("state="+request.readyState);
+ 				if (request.readyState == 4) {
+ 					if (request.status == 200) {
+ 						that.debug(request);
+ 						if (that.Nz(getXML)) {
+ 							callBack(request.responseXML, arg, request)
+ 						} else {
+ 							callBack(request.responseText, arg, request)
+ 						}
+ 						request.onreadystatechange = null
+ 						request = null
+ 					} else {
+ 						that.debug("fetch("+request.status+")=> "+url)
+ 						request.onreadystatechange = null
+ 						request = null
+ 					}
+ 				}
+ 			} catch(e){ that.debug(e); }
+ 		}
+ 		request.send("");
+ 	} catch (e) { that.debug(e) }
+ }
+ 
+ nsMPM.mpm_openDialog = function(url, id) {
+ 	let that = this;
+ 	var features = "chrome,dialog=yes,resizable=yes"
+ 	if (id=="settings") features += ",titlebar,toolbar"
+ 	var win = that.winw.openWindow(that.winw.activeWindow, url, that.Nz(id, url),features, null);
+ }
+ 
+ nsMPM.openReuseByURL = function(url) {
+ 	let that = this;
+ 	var wm = null;
+ 	try {
+ 		wm = that.Cc["@mozilla.org/appshell/window-mediator;1"]
+ 			.getService(that.Ci.nsIWindowMediator);
+ 		
+ 	} catch(e) {
+ 		that.debug(e);
+ 	}
+ 	var browserEnumerator = wm.getEnumerator("navigator:browser");
+ 	// Check each browser instance for our URL
+ 	var found = false;
+ 	try {
+ 		while (!found && browserEnumerator.hasMoreElements()) {
+ 			var browser = browserEnumerator.getNext();
+ 			var browserInstance = browser.getBrowser();
+ 
+ 			// Check each tab of this browser instance
+ 			var numTabs = browserInstance.tabContainer.childNodes.length;
+ 			for (var index = 0; index < numTabs; index++) {
+ 				var currentBrowser = browserInstance.getBrowserAtIndex(index);
+ 				if (url == currentBrowser.currentURI.spec) {
+ 					// The URL is already opened. Select this tab.
+ 					browserInstance.selectedTab = browserInstance.tabContainer.childNodes[index];
+ 					// Focus *this* browser
+ 					browser.focus();
+ 					browserInstance.focus();
+ 					that.debug("browser already in tab");
+ 					// wrapped is compulsory otherwise we can't right click on the statusbar
+ 					// to display album details and perform queries.
+ 					var win = currentBrowser.contentWindow.wrappedJSObject;
+ 					found = true;
+ 					break;
+ 				}
+ 			}
+ 		}
+ 		if (!found) {
+ 			var openInTab = that.prefs.get("launch_in_browser", false);
+ 			var recent = (openInTab) ? wm.getMostRecentWindow("navigator:browser") : false;
+ 			if (recent) {
+ 				recent.focus();
+ 				browserInstance = recent.getBrowser();
+ 				browserInstance.selectedTab = browserInstance.addTab(url);
+ 				browserInstance.focus();
+ 				var currentBrowser = browserInstance.getBrowserForTab(browserInstance.selectedTab);
+ 				// wrapped is compulsory otherwise we can't right click on the statusbar
+ 				// to display album details and perform queries.
+ 				var win = currentBrowser.contentWindow.wrappedJSObject;
+ 			} else {
+ 				var win = that.winw.getWindowByName(url, null);
+ 				if (!win) win = that.winw.openWindow(null, url, url, null, null);
+ 				win.focus();
+ 			}
+ 		}
+ 		return win;
+ 	} catch (e) {
+ 		that.debug(e);
+ 	}
+ 	return null;
+ }
+ 
+ nsMPM.openReuseByAttribute = function(url, attrName) {
+ 	let that = this;
+ 
+ 	var wm = that.Cc["@mozilla.org/appshell/window-mediator;1"].getService(that.Ci.nsIWindowMediator);
+ 	attrName = that.Nz(attrName, 'mpm-unknown-tab')
+ 	try {
+ 		for (var found = false, 
+ 			index = 0, 
+ 			browserInstance = wm.getEnumerator('navigator:browser').getNext().getBrowser(); 
+ 			index < browserInstance.mTabContainer.childNodes.length && !found; index++) {
+ 			var currentTab = browserInstance.mTabContainer.childNodes[index];
+ 			if (currentTab.hasAttribute(attrName)) {
+ 				browserInstance.selectedTab = currentTab;
+ 				browserInstance.focus();
+ 				found = true;
+ 			}
+ 		}
+ 		if (!found) {
+ 			var browserEnumerator = wm.getEnumerator("navigator:browser");
+ 			var browserInstance = browserEnumerator.getNext().getBrowser();
+ 			var newTab = browserInstance.addTab(url);
+ 			newTab.setAttribute(attrName, "xyz");
+ 			browserInstance.selectedTab = newTab;
+ 			browserInstance.focus();
+ 		}
+ 	} catch (e) {
+ 		that.winw.openWindow(null, url, attrName, null, null)
+ 	}
+ }
+ 
+ nsMPM.guessTags = function(song) {
+ 	let that = this;
+ 	
+ 	_artist = ""
+ 	_album = ""
+ 	_title = ""
+ 	_track = ""
+ 	track = that.Nz(song.Track, "")
+ 	title = that.Nz(song.Title, "")
+ 	artist = that.Nz(song.Artist, "")
+ 	album = that.Nz(song.Album, "")
+ 	try {
+ 		myfile = song.file.match(/[^\/]+$/)[0].replace(/\.[a-zA-Z0-9]+$/, "")
+ 		_title = myfile
+ 		myfile = myfile.replace(/\(.*\)/g, "").replace(/_/g, " ")
+ 		s = myfile.split("-")
+ 		l = s.length
+ 		
+ 		for (var i=0;i<l;i++) {
+ 			if (/^[0-9\.\/\s]+$/.test(s[i])) {
+ 				_track = s.splice(i,1)
+ 				if (typeof(_track) == 'string')
+ 					_track = _track.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
+ 				break
+ 			}
+ 		}
+ 
+ 		if (s.length > 0) _title = s.pop()
+ 		if (s.length > 0) _artist = s.shift()
+ 		if (s.length > 0) _album = s.join("-")
+ 		
+ 		if (track == "") song.Track = _track
+ 		if (title == "") song.Title = _title.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
+ 		if (artist == "") song.Artist = _artist.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
+ 		if (album == "") song.Album = _album.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
+ 	} catch (e) {that.debug(e)}
+ 	return song
+ }
+ nsMPM.updateStatusBarAllStyles = function(wStorage) {
+ 	let that = this;
+ 	that.updateStatusBarStyles(wStorage);
+ 	that.updateStatusBarElementsStyles(wStorage,'pref','launch',null);
+ 	that.updateStatusBarElementsStyles(wStorage,'pref','playback',null);
+ 	that.updateStatusBarElementsStyles(wStorage,'pref','currentsong',null);
+ 	that.updateStatusBarElementsStyles(wStorage,'pref','playlist',null);
+ 	that.updateStatusBarElementsStyles(wStorage,'pref','settings',null);
+ }
+ nsMPM.updateStatusBarElementsStyles = function (wStorage, domain, topic, hide){
+ 	let that = this;
+ 	if ( !topic || topic == '') {
+ 		that.debug('Call to updateStatusBarElementsStyles with no topic');
+ 		return;
+ 	}
+ 	switch (domain) {
+ 		case 'force':
+ 			switch(topic) {
+ 				case 'playback':
+ 					wStorage.document.getElementById('mpm_sb_controls').hidden = hide;
+ 					wStorage.document.getElementById('mpm_sb_volume').hidden = hide;
+ 				break;
+ 				case 'currentsong':
+ 					wStorage.document.getElementById('mpm_sb_currentsong').hidden = hide;
+ 					wStorage.document.getElementById('mpm_sb_playlist').hidden = hide;
+ 					wStorage.document.getElementById('mpm_sb_currentsongb').collapsed = hide;
+ 					wStorage.document.getElementById('mpm_sb_playlistb').collapsed = hide;
+ 				break;
+ 				case 'playlist':
+ 					wStorage.document.getElementById('sb_playlist_menu').collapsed = hide;
+ 					wStorage.document.getElementById('sb_playlist_box').collapsed = hide;
+ 
+ 				break;
+ 				default:
+ 					that.debug('Call to updateStatusBarElementsStyles() with unknown domain:topic: '+domain+':'+topic);
+ 				break;
+ 			}
+ 		break;
+ 		case 'pref':
+ 			switch(topic) {
+ 				case 'launch':
+ 					var h = that.prefs.get('sb_launch_hide', false);
+ 					wStorage.document.getElementById('mpm_sb_launch').hidden = h;
+ 				break;
+ 				case 'playback':
+ 					if  (that.mpd._socket == null) return;
+ 					var h = that.prefs.get('sb_controls_hide', false);
+ 					wStorage.document.getElementById('mpm_sb_controls').hidden = h;
+ 					wStorage.document.getElementById('mpm_sb_volume').hidden = h;
+ 				break;
+ 				case 'currentsong':
+ 					if  (that.mpd._socket == null) return;
+ 					var h = that.prefs.get('sb_currentsong_hide', false);
+ 					wStorage.document.getElementById('mpm_sb_currentsong').collapsed = h;
+ 					wStorage.document.getElementById('mpm_sb_playlist').collapsed = !h;
+ 					wStorage.document.getElementById('mpm_sb_box_resizer').collapsed = h;
+ 					wStorage.document.getElementById('mpm_sb_currentsongb').collapsed = h;
+ 					wStorage.document.getElementById('mpm_sb_playlistb').collapsed = !h;
+ 					wStorage.document.getElementById('mpm_sb_box_resizerb').collapsed = h;
+ 				break;
+ 				case 'playlist':
+ 					if  (that.mpd._socket == null) return;
+ 					var menu = that.prefs.get('sb_playlist_menu', false);
+ 					wStorage.document.getElementById('sb_playlist_menu').collapsed = !menu;
+ 					wStorage.document.getElementById('sb_playlist_box').collapsed = menu;
+ 				break;
+ 				case 'settings':
+ 					var h = that.prefs.get('sb_settings_hide', false);
+ 					wStorage.document.getElementById('mpm_sb_servers').collapsed = h;
+ 					wStorage.document.getElementById('mpm_sb_servers').hidden = h;
+ 				break;
+ 				default:
+ 					that.debug('Call to updateStatusBarElementsStyles() with unknown domain:topic: '+domain+':'+topic);
+ 				break;
+ 			}
+ 		break;
+ 		default:
+ 			that.debug('Call to updateStatusBarElementsStyles() with unknown domain:topic: '+domain+':'+topic);
+ 		
+ 	}
+ }
+ 
+ nsMPM.updateStatusBarStyles = function(wStorage) {
+ 	let that = this;
+ 	var index = that.prefs.get("statusbar_position", 0);
+ 	if (index < 0) index = 0;
+ 	that.debug('status-bar index: '+index);	
+ 	try
+ 	{
+ 		var statusBar = wStorage.document.getElementById("status-bar");
+ 		var children = statusBar.childNodes;
+ 
+ 		if ( wStorage.statusbar == null )
+ 			wStorage.statusbar = wStorage.document.getElementById("mpm_status-bar_controls");
+ 		
+ 		if ( wStorage.statusbar == null ) that.debug("mpm_status-bar_controls cannot be found")
+  
+ 		try {
+ 			statusBar.removeChild(wStorage.statusbar);
+ 		} catch(e){that.debug("cannot remove status-bar item");}
+ 
+ 		if ( that.prefs.get('statusbar_hide',false) == false ) {
+ 			// status-bar position
+ 			if ((children.length == 0) || (index >= children.length)){
+ 				statusBar.appendChild(wStorage.statusbar);
+ 			} else {
+ 				statusBar.insertBefore(wStorage.statusbar, children[index-1]);
+ 			}
+ 			
+ 			// current song styles
+ 			var newWidth = that.prefs.get('sb_song_width',150);
+ 			that.debug("status-bar title width changed: "+ newWidth);
+ 			wStorage.document.getElementById('mpm_sb_Titleb').setAttribute('width',newWidth);
+ 			wStorage.document.getElementById('mpm_sb_Titleb').child.setAttribute('width',newWidth);
+ 			wStorage.document.getElementById('mpm_sb_Title').setAttribute('width',newWidth);
+ 			wStorage.document.getElementById('mpm_sb_Title').child.setAttribute('width',newWidth);
+ 		} else {
+ 			that.debug("Status-bar not displayed based on prefs");
+ 		}
+ 	} catch(e) {
+ 		that.debug(e);
+ 		that.debug('doc/document:');
+ 		that.debug(doc);
+ 	}
+ }
+ 
+ nsMPM.chooseFolder = function(win, prefName) {
+ 	let that = this;
+ 	try {
+ 		const nsIFilePicker = that.Ci.nsIFilePicker;
+ 		const nsILocalFile = that.Ci.nsILocalFile;
+ 
+ 		var fp = that.Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+ 		var dnldMgr = that.Cc["@mozilla.org/download-manager;1"].getService(that.Ci.nsIDownloadManager);
+ 
+ 		var title = "My title";
+ 		fp.init(win, title, nsIFilePicker.modeGetFolder);
+ 		fp.appendFilters(nsIFilePicker.filterAll);
+ 
+ 		fp.displayDirectory = dnldMgr.defaultDownloadsDirectory;
+ 
+ 		if (fp.show() == nsIFilePicker.returnOK) {
+ 			if ( typeof(prefName) != 'string' ) { that.debug('invalid prefName'); return; }
+ 			if ( prefName.length < 1 ) { that.debug('invalid prefName'); return; }
+ 			var forderPref = win.document.getElementById(prefName);
+ 			var file = fp.fileURL;
+ 			forderPref.value = file.spec;
+ 		}
+ 	} catch(e) { that.debug(e); }
+ }
+ 
+ // update the UI from the prefs at load time
+ nsMPM.updateCustomArtInterfacePref = function(doc) {
+ 	let that = this;
+ 
+ 	try {
+ 		var use_customPref = doc.getElementById("use_custom");
+ 		var tbCoverUrl = doc.getElementById("tbCoverUrl");
+ 		var btnBrowse = doc.getElementById("btnCustomBrowseLocalFile");
+ 		
+ 		if ( use_customPref.value == true ) {
+ 			tbCoverUrl.disabled = false;
+ 			btnBrowse.disabled = false;
+ 		} else {
+ 			tbCoverUrl.disabled = true;
+ 			btnBrowse.disabled = true;
+ 		}
+ 	} catch(e) { that.debug(e); }
+ }
+ 
+ // update the UI on user click
+ nsMPM.updateCustomArtInterface = function(doc) {
+ 	let that = this;
+ 	try {
+ 		var cbUseCustom = doc.getElementById("cbUseCustom");
+ 		var tbCoverUrl = doc.getElementById("tbCoverUrl");
+ 		var btnBrowse = doc.getElementById("btnCustomBrowseLocalFile");
+ 
+ 		if ( cbUseCustom.checked == true ) {
+ 			tbCoverUrl.disabled = false;
+ 			btnBrowse.disabled = false;
+ 		} else {
+ 			tbCoverUrl.disabled = true;
+ 			btnBrowse.disabled = true;
+ 		}
+ 	} catch(e) { that.debug(e); }
+ }
+ nsMPM.updateIntervalInterfacePref = function(doc) {
+ 	let that = this;
+ 
+ 	try {
+ 		var adapt_intervalPref = doc.getElementById("adapt_interval");
+ 		var tbUpdate = doc.getElementById("update");
+ 		
+ 		if ( adapt_intervalPref.value == true ) tbUpdate.disabled = true;
+ 		else tbUpdate.disabled = false;
+ 	} catch(e) { that.debug(e); }
+ }
+ nsMPM.updateIntervalInterface = function (doc) {
+ 	let that = this;
+ 
+ 	try {
+ 		var cbCheck_adapt = doc.getElementById("check_adapt");
+ 		var tbUpdate = doc.getElementById("update");
+ 
+ 		if ( cbCheck_adapt.checked == true ) tbUpdate.disabled = true;
+ 		else tbUpdate.disabled = false;
+ 	} catch(e) { that.debug(e); }
+ }
+ nsMPM.updateStatusbarInterfacePref = function(doc) {	
+ 	let that = this;
+ 	try {
+ 		var statusbar_hidePref = doc.getElementById("statusbar_hide");
+ 		var cbLaunch = doc.getElementById("check_launch");
+ 		var cbControls = doc.getElementById("check_ctrl");
+ 		var cbCurrentSong = doc.getElementById("check_cs");
+ 		var cbSettings = doc.getElementById("check_settings");
+ 		var cbPlaylistMenu = doc.getElementById("check_playlist_menu");
+ 		var lbPosition = doc.getElementById("label_position");
+ 		var tbPosition = doc.getElementById("txt_statusbar_position");
+ 		
+ 		if ( statusbar_hidePref.value == true ){
+ 			cbLaunch.disabled = cbControls.disabled = cbCurrentSong.disabled = cbSettings.disabled = cbPlaylistMenu.disabled = lbPosition.disabled = tbPosition.disabled = true;
+ 		} else {
+ 			cbLaunch.disabled = cbControls.disabled = cbCurrentSong.disabled = cbSettings.disabled = cbPlaylistMenu.disabled = lbPosition.disabled = tbPosition.disabled = false;
+ 		}		
+ 	} catch(e){ that.debug(e); }
+ }
+ nsMPM.updateStatusbarInterface = function (doc) {
+ 	let that = this;
+ 	try {
+ 		var cbStatusbarHide = doc.getElementById("check_statusbar_hide");
+ 		var cbLaunch = doc.getElementById("check_launch");
+ 		var cbControls = doc.getElementById("check_ctrl");
+ 		var cbCurrentSong = doc.getElementById("check_cs");
+ 		var cbSettings = doc.getElementById("check_settings");
+ 		var cbPlaylistMenu = doc.getElementById("check_playlist_menu");
+ 		var lbPosition = doc.getElementById("label_position");
+ 		var tbPosition = doc.getElementById("txt_statusbar_position");
+ 		
+ 		if ( cbStatusbarHide.checked == true ){
+ 			cbLaunch.disabled = cbControls.disabled = cbCurrentSong.disabled = cbSettings.disabled = cbPlaylistMenu.disabled = lbPosition.disabled = tbPosition.disabled = true;
+ 		} else {
+ 			cbLaunch.disabled = cbControls.disabled = cbCurrentSong.disabled = cbSettings.disabled = cbPlaylistMenu.disabled = lbPosition.disabled = tbPosition.disabled = false;
+ 		}		
+ 	} catch(e){ that.debug(e); }	
+ }
+ nsMPM.updateDownloadInterface = function(doc){
+ 	let that = this;
+ 	try {
+ 		var cbDlIntegrate = doc.getElementById("check_dl_integrate");
+ 		var rDlActionAdd = doc.getElementById("rDlActionAdd");
+ 		var rDlActionrepl = doc.getElementById("rDlActionRepl");
+ 		var rDlAfterNothing = doc.getElementById("rDlAfterNothing");
+ 		var rDlAfterPlayStop = doc.getElementById("rDlAfterPlayStop");
+ 		var rDlAfterPlayNow = doc.getElementById("rDlAfterPlayNow");
+ 		
+ 		if ( cbDlIntegrate.checked == true )	{
+ 			rDlAfterNothing.disabled = rDlAfterPlayStop.disabled = rDlAfterPlayNow.disabled = false;
+ 			rDlActionrepl.disabled = rDlActionAdd.disabled = false;
+ 		} else {
+ 			rDlAfterNothing.disabled = rDlAfterPlayStop.disabled = rDlAfterPlayNow.disabled = true;
+ 			rDlActionrepl.disabled = rDlActionAdd.disabled = true;
+ 		}
+ 	}catch(e){ that.debug(e); }
+ }
+ 
+ nsMPM.updateDownloadInterfacePref = function(doc){
+ 	let that = this;
+ 	try {
+ 		var dl_integratePref = doc.getElementById("dl_integrate");
+ 		var rDlActionAdd = doc.getElementById("rDlActionAdd");
+ 		var rDlActionrepl = doc.getElementById("rDlActionRepl");
+ 		var rDlAfterNothing = doc.getElementById("rDlAfterNothing");
+ 		var rDlAfterPlayStop = doc.getElementById("rDlAfterPlayStop");
+ 		var rDlAfterPlayNow = doc.getElementById("rDlAfterPlayNow");
+ 		
+ 		if ( dl_integratePref.value == true )	{
+ 			rDlAfterNothing.disabled = rDlAfterPlayStop.disabled = rDlAfterPlayNow.disabled = false;
+ 			rDlActionrepl.disabled = rDlActionAdd.disabled = false;
+ 		} else {
+ 			rDlAfterNothing.disabled = rDlAfterPlayStop.disabled = rDlAfterPlayNow.disabled = true;
+ 			rDlActionrepl.disabled = rDlActionAdd.disabled = true;
+ 		}
+ 	}catch(e){ that.debug(e); }
+ }
+ 
+ nsMPM.updateAmazonInterfacePref = function(doc) {
+ 	let that = this;
+ 	try {
+ 		var use_amazonPref = doc.getElementById("use_amazon");
+ 		var tbSaveCoverUrl = doc.getElementById("tbSaveCoverUrl");
+ 		var btnBrowse = doc.getElementById("btnAmazonBrowseLocalFile");
+ 
+ 		if ( use_amazonPref.value == 2 ) {
+ 			tbSaveCoverUrl.disabled = false;
+ 			btnBrowse.disabled = false;
+ 		} else {
+ 			tbSaveCoverUrl.disabled = true;
+ 			btnBrowse.disabled = true;
+ 		}
+ 	} catch(e) { that.debug(e); }
+ }
+ 
+ nsMPM.updateAmazonInterface = function(doc) {
+ 	let that = this;
+ 	try {
+ 		var rgUseAmazon = doc.getElementById("rgUseAmazon");
+ 		var tbSaveCoverUrl = doc.getElementById("tbSaveCoverUrl");
+ 		var btnBrowse = doc.getElementById("btnAmazonBrowseLocalFile");
+ 
+ 		if ( rgUseAmazon.value == 2 ) {
+ 			tbSaveCoverUrl.disabled = false;
+ 			btnBrowse.disabled = false;
+ 		} else {
+ 			tbSaveCoverUrl.disabled = true;
+ 			btnBrowse.disabled = true;
+ 		}
+ 	} catch(e) { that.debug(e); }
+ }
+ 
+ nsMPM.togglePlaylistBar = function(doc) {
+ 	let that = this;
+ 
+ 	var b = doc.getElementById("mpm_playlist_sb");
+ 	var pl = doc.getElementById("mpm_mw_playlist_box");
+ 	var s = doc.getElementById("mpm_playlist_splitter");
+ 	if (!b.collapsed) pl.saveColumns();
+ 	else pl.showCurrent();
+ 	
+ 	if (parseInt(b.height) < 1) {
+ 		s.collapsed = !s.collapsed;
+ 		b.collapsed = !b.collapsed;
+ 		that.slideevent.incr = 10;
+ 		that.slideevent.end = 110;
+ 	} else {
+ 		that.slideevent.incr = -10;
+ 		that.slideevent.end = 0;
+ 	}
+ 	that.slideevent.doc = doc;
+ 	that.slidetimer.initWithCallback(that.slideevent,100,that.Ci.nsITimer.TYPE_REPEATING_SLACK);
+ }
+ 
+ nsMPM.prefObserver = function(prefName, changeAction) {
+ 	this.action = changeAction
+ 	this.register = function(){
+ 		this._branch = nsMPM.prefs.branch;
+ 		this._branch.QueryInterface(nsMPM.Ci.nsIPrefBranchInternal);
+ 		this._branch.addObserver("", this, false);
+ 	},
+ 	this.unregister = function(){
+ 		if (!this._branch)
+ 			return;
+ 		this._branch.removeObserver("", this);
+ 	},
+ 	this.observe = function(aSubject, aTopic, aData){
+ 		if (aTopic != "nsPref:changed")
+ 			return;
+ 		// aSubject is the nsIPrefBranch we're observing (after appropriate QI)
+ 		// aData is the name of the pref that's been changed (relative to aSubject)
+ 		if (aData == prefName) this.action()
+ 	}
+ }
+ 
+ nsMPM.prefs = {
+ 	branch : Components.classes["@mozilla.org/preferences-service;1"]
+ 			.getService(Components.interfaces.nsIPrefService)
+ 			.getBranch("extensions.mpm."),
+ 	get : function(strPref, def) {
+ 		try{
+ 			switch (this.branch.getPrefType(strPref)) {
+ 				case this.branch.PREF_STRING :
+ 					return this.branch.getCharPref(strPref);
+ 				case this.branch.PREF_INT :
+ 					return this.branch.getIntPref(strPref);
+ 				case this.branch.PREF_BOOL :
+ 					return this.branch.getBoolPref(strPref);
+ 				default :
+ 					def = nsMPM.Nz(def)
+ 					this.set(strPref, def);
+ 					return def;
+ 			}
+ 		} catch(e){ nsMPM.debug(e); }
+ 		return 'undefined';
+ 	},
+ 	isPref : function (strPref) {
+ 		try {
+ 			if ( !strPref ) return false;
+ 			if ( this.branch.getPrefType(strPref) != this.branch.PREF_INVALID ) return true;
+ 			return false;
+ 		} catch(e) { 
+ 			nsMPM.debug(e);
+ 			return false; 
+ 		}
+ 	},
+ 	getObserver : function (prefName, prefAction) {
+ 		var po = new nsMPM.prefObserver(prefName, prefAction)
+ 		po.register()
+ 		return po
+ 	},
+ 	clear : function(strPref) {
+ 		try {
+ 			this.branch.clearUserPref(strPref);
+ 		} catch(e) { return; }
+ 	},
+ 	set : function(strPref, val) {
+ 		switch (this.branch.getPrefType(strPref)) {
+ 			case this.branch.PREF_STRING :
+ 				this.branch.setCharPref(strPref, val);
+ 				break;
+ 			case this.branch.PREF_INT :
+ 				this.branch.setIntPref(strPref, val);
+ 				break;
+ 			case this.branch.PREF_BOOL :
+ 				this.branch.setBoolPref(strPref, val);
+ 				break;
+ 			default :
+ 				if (typeof(val) != 'undefined') {
+ 					switch (typeof(val)) {
+ 						case 'string' :
+ 							this.branch.setCharPref(strPref, val);
+ 							break;
+ 						case 'number' :
+ 							this.branch.setIntPref(strPref, val);
+ 							break;
+ 						case 'boolean' :
+ 							this.branch.setBoolPref(strPref, val);
+ 							break;
+ 						default :
+ 							this.branch.setCharPref(strPref, val.toSource());
+ 							break;
+ 					}
+ 				}
+ 		}
+ 	}
+ }
+ nsMPM.slideevent = {
+ 	incr : 0,
+ 	end : 0,
+ 	doc : null,
+ 	notify: function(slidetimer) {		
+ 		if (this.end < 1) this.end = 0;
+ 		if ( this.incr == 0 ) {
+ 			// nsMPM.debug("canceled"+this.incr+"-"+this.end);
+ 			slidetimer.cancel();
+ 			return;
+ 		}
+ 		try {
+ 			var b = this.doc.getElementById("mpm_playlist_sb");
+ 			// nsMPM.debug("slideevent: incr="+this.incr+", end="+this.end+", b.height="+b.height+", b.boxObject.height="+b.boxObject.height);
+ 			b.height = parseInt(b.height) + this.incr;
+ 		} catch(e) {
+ 			nsMPM.debug(e);
+ 			slidetimer.cancel();
+ 			return;
+ 		}
+ 		if (this.incr > 0) {
+ 			if (b.height >= this.end) slidetimer.cancel();
+ 		} else {
+ 			if (b.height <= this.end) {
+ 				slidetimer.cancel();
+ 				b.collapsed = !b.collapsed;
+ 				var s = this.doc.getElementById("mpm_playlist_splitter");
+ 				s.collapsed = !s.collapsed;
+ 			}
+ 		}
+ 	}
+ }
+ nsMPM.winStorage = function(win,doc) {
+ 	if ( typeof(win) == 'undefinied' || typeof(doc) == 'undefined') return
+ 	nsMPM.instance_count++;
+ 	this.instance = nsMPM.instance_count;
+ 	this.obs = null;
+ 	this.obsVol = null;
+ 	this.csPrefObserver = null;
+ 	this.window = win;
+ 	this.document = doc;
+ 	this.mpm = null;
+ 	this.statusbar = null;
+ }
+ 
+ nsMPM.resizeHandler = {
+ 	bResizing : false,
+ 	startPosX : null,
+ 	panelElem : null,
+ 	lastWidth : null,
+ 	minWidth : 25,
+ 	startPanelWidth: null,
+ 	win: null,
+ 	
+ 	onMouseMove: function(event){
+ 		try{
+ 			if (!nsMPM.resizeHandler.bResizing) return;
+ 			var deltaX = event.screenX - nsMPM.resizeHandler.startPosX;
+ 			
+ 			var newWidth = 1*nsMPM.resizeHandler.startPanelWidth + deltaX;
+ 			if (newWidth > nsMPM.resizeHandler.minWidth) {
+ 				nsMPM.resizeHandler.panelElem.setAttribute('width', newWidth);
+ 				nsMPM.resizeHandler.panelElem.child.setAttribute('width', newWidth);
+ 				nsMPM.resizeHandler.lastWidth = newWidth;
+ 			}
+ 		} catch(e){nsMPM.debug(e);}
+ 	},
+ 	onMouseDown: function(win,event){
+ 		/* the "win" is important to listen the mouse mvts globally */
+ 		try{
+ 			if (nsMPM.resizeHandler.bResizing) return;
+ 			nsMPM.resizeHandler.bResizing = true;
+ 			nsMPM.resizeHandler.startPosX = event.screenX;
+ 			nsMPM.resizeHandler.panelElem  = event.target.previousSibling.lastChild;
+ 			nsMPM.resizeHandler.startPanelWidth = nsMPM.resizeHandler.panelElem.getAttribute('width');
+ 			win.addEventListener("mouseup", nsMPM.resizeHandler.onMouseUp, false);
+ 			win.addEventListener("mousemove", nsMPM.resizeHandler.onMouseMove, false);
+ 			nsMPM.resizeHandler.win = win;
+ 		} catch(e){nsMPM.debug(e);}
+ 	},
+ 	onMouseUp: function(event){
+ 		try {
+ 			nsMPM.resizeHandler.bResizing = false;
+ 			if ( nsMPM.resizeHandler.startPanelWidth != nsMPM.resizeHandler.lastWidth
+ 				&& nsMPM.resizeHandler.lastWidth != null ) {
+ 				if ( nsMPM.resizeHandler.lastWidth < nsMPM.resizeHandler.minWidth )
+ 					nsMPM.resizeHandler.lastWidth = nsMPM.resizeHandler.minWidth;
+ 				nsMPM.prefs.set('sb_song_width', nsMPM.resizeHandler.lastWidth);
+ 			}
+ 			if ( nsMPM.resizeHandler.win ) {
+ 				nsMPM.resizeHandler.win.removeEventListener("mouseup",nsMPM.resizeHandler.onMouseUp,false);
+ 				nsMPM.resizeHandler.win.removeEventListener("mousemove",nsMPM.resizeHandler.onMouseMove,false);
+ 			}
+ 		} catch(e){nsMPM.debug(e);}
+ 	}
+ }
+ nsMPM.handleDowloadURL = function(urlObj){
+ 	let that = this;
+ 	try {
+ 		var action = 'add';
+ 		var lastsong = that.mpd.playlistlength;
+ 		
+ 		if ( that.prefs.get('dl.action',1) == 2) action = 'replace';
+ 		if ( that.processDowloadURL(urlObj, action) ) {
+ 			var after = that.prefs.get('dl.after',0);
+ 			if ( after == 0 ) return; // do nothing
+ 
+ 			if ( after == 1 && that.mpd.state == 'stop' ) { // play if stopped
+ 				if ( action == 'replace') that.mpd.doCmd('play');
+ 				else that.mpd.doCmd('play '+lastsong);
+ 			}
+ 
+ 			if ( after == 2 ) { // play now
+ 				if ( action == 'replace') that.mpd.doCmd('play');
+ 				else that.mpd.doCmd('play '+lastsong);
+ 			}
+ 		}
+ 	} catch(e){ that.debug(e); }
+ }
+ 
+ nsMPM.processDowloadURL = function(urlObj, action){
+ 	let that = this;
+ 	var url = urlObj.spec;
+ 	if ( typeof(action) == 'undefined' ) action = 'add';
+ 	that.debug('processDowloadURL('+urlObj.spec+','+action+')');
+ 	
+ 	function retrieveData(stream){
+ 		try {
+ 			if (!stream) return null;
+ 			var size = 0;
+ 			var file_data = "";
+ 			var bstream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
+ 			bstream.setInputStream(stream);
+ 			while((size = bstream.available())) file_data += bstream.readBytes(size);
+ 			return file_data;
+ 		} catch(e){ that.debug(e); }
+ 		return null;
+ 	}
+ 	try {
+ 		if ( urlObj.fileExtension ){
+ 			switch(urlObj.fileExtension.toLocaleLowerCase()){
+ 				case "mp3" :
+ 					if ( action == 'replace') that.mpd.doCmd('clear');
+ 					that.mpd.doCmd('add "' + url + '"');
+ 					return 1;
+ 					break;
+ 				case "ogg" :
+ 					if ( action == 'replace') that.mpd.doCmd('clear');
+ 					that.mpd.doCmd('add "' + url + '"');
+ 					return 1;
+ 					break;
+ 				case "wav" :
+ 					if ( action == 'replace') that.mpd.doCmd('clear');
+ 					that.mpd.doCmd('add "' + url + '"');
+ 					return 1;
+ 					break;
+ 				case "flac" :
+ 					if ( action == 'replace') that.mpd.doCmd('clear');
+ 					that.mpd.doCmd('add "' + url + '"');
+ 					return 1;
+ 					break;
+ 				case "aac" :
+ 					if ( action == 'replace') that.mpd.doCmd('clear');
+ 					that.mpd.doCmd('add "' + url + '"');
+ 					return 1;
+ 					break;
+ 				case "mod" :
+ 					if ( action == 'replace') that.mpd.doCmd('clear');
+ 					that.mpd.doCmd('add "' + url + '"');
+ 					return 1;
+ 					break;
+ 				case "wma" :
+ 					if ( action == 'replace') that.mpd.doCmd('clear');
+ 					that.mpd.doCmd('add "' + url + '"');
+ 					return 1;
+ 					break;
+ 			}
+ 			
+ 		}
+ 		// these files require processing and local download
+ 		var ioserv = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
+ 		var channel = ioserv.newChannel(url, 0, null);
+ 		var stream = channel.open();
+ 		if (channel instanceof Components.interfaces.nsIHttpChannel && channel.responseStatus != 200) {
+ 			that.debug("Failed to retrieve element: "+url);
+ 			return false;
+ 		} else {
+ 			try {
+ 				var contenttype = '';
+ 				if ( typeof(channel.contentType) != 'undefined') contenttype = channel.contentType;
+ 				else channel.getResponseHeader('Content-Type');
+ 				if ( contenttype ){
+ 					switch(contenttype){
+ 						case "audio/x-scpls" :
+ 							return that.mpd.load_pls_stream(retrieveData(stream), action);
+ 						break;
+ 						case "audio/x-mpegurl" :
+ 							return that.mpd.load_m3u_stream(retrieveData(stream), action);
+ 						break;
+ 						case "application/xspf+xml" :
+ 							try {
+ 								var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
+ 								var xml = parser.parseFromStream(stream, null, -1, "application/xml");
+ 								return that.mpd.load_xspf_stream(xml, action);
+ 							} catch(e){ that.debug(e); }
+ 							return false;
+ 						break;
+ 					}
+ 				}
+ 			} catch(e){ that.debug(e); }
+ 			// in case the server did not reported proper mime type but the extension matched (maybe)
+ 			switch (url.substr(-4).toLocaleLowerCase()) {
+ 				case ".pls" :
+ 					return that.mpd.load_pls_stream(retrieveData(stream), action);
+ 				break;
+ 				case ".m3u" :
+ 					return that.mpd.load_m3u_stream(retrieveData(stream), action);
+ 				break;
+ 				case "xspf" :
+ 					try {
+ 						var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
+ 						var xml = parser.parseFromStream(stream, null, -1, "application/xml");
+ 						return that.mpd.load_xspf_stream(xml, action);
+ 					} catch(e){ that.debug(e); }
+ 					return false;
+ 				break;
+ 			}
+ 			that.debug("The specified URL isn't supported: "+url);
+ 		}
+ 	} catch(e){ that.debug(e); }
+ 	return false;
+ }
+ // dependent js modules
+ // declare holder in mpmCommon.js
+ if (nsMPM.mpmMenu == null) Components.utils.import("chrome://minion/content/mpmMenu.js",nsMPM);
+ if (nsMPM.mpd == null) Components.utils.import("chrome://minion/content/mpd.js",nsMPM);
+ if (nsMPM.mpmUpgrade == null ) Components.utils.import("chrome://minion/content/mpmUpgrade.js",nsMPM);
diff -c -r -N minion.orig//chrome/content/playlistBindings.xml minion.patched//chrome/content/playlistBindings.xml
*** minion.orig//chrome/content/playlistBindings.xml	2012-03-30 23:07:40.153062918 +0200
--- minion.patched//chrome/content/playlistBindings.xml	2012-03-30 22:54:31.937101233 +0200
***************
*** 119,126 ****
                  readonly="true"/>
              <constructor>
                  <![CDATA[
!                 Components.utils.import("resource://minion/mpmUtils.js");
!                 Components.utils.import("resource://minion/trees.js");
  
                  var me = this
                  function applyView() {
--- 119,126 ----
                  readonly="true"/>
              <constructor>
                  <![CDATA[
!                 Components.utils.import("chrome://minion/content/mpmUtils.js");
!                 Components.utils.import("chrome://minion/content/trees.js");
  
                  var me = this
                  function applyView() {
diff -c -r -N minion.orig//chrome/content/saveas.js minion.patched//chrome/content/saveas.js
*** minion.orig//chrome/content/saveas.js	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/content/saveas.js	2012-03-30 23:00:39.117083384 +0200
***************
*** 1,4 ****
! Components.utils.import("resource://minion/mpmUtils.js");
  
  addEventListener('load', function() {
  	let dlg = dialog;
--- 1,4 ----
! Components.utils.import("chrome://minion/content/mpmUtils.js");
  
  addEventListener('load', function() {
  	let dlg = dialog;
diff -c -r -N minion.orig//chrome/content/servers.xul minion.patched//chrome/content/servers.xul
*** minion.orig//chrome/content/servers.xul	2012-03-30 23:07:40.153062918 +0200
--- minion.patched//chrome/content/servers.xul	2012-03-30 22:57:20.853093022 +0200
***************
*** 16,22 ****
          style="overflow: auto">
      <script>
      <![CDATA[
!         Components.utils.import("resource://minion/mpmUtils.js");
          var xul = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  		
          function addServerRow (index) {
--- 16,22 ----
          style="overflow: auto">
      <script>
      <![CDATA[
!         Components.utils.import("chrome://minion/content/mpmUtils.js");
          var xul = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  		
          function addServerRow (index) {
diff -c -r -N minion.orig//chrome/content/settings.xul minion.patched//chrome/content/settings.xul
*** minion.orig//chrome/content/settings.xul	2012-03-30 23:07:40.153062918 +0200
--- minion.patched//chrome/content/settings.xul	2012-03-30 22:58:43.353089011 +0200
***************
*** 10,16 ****
  	<script>
  	<![CDATA[
  	// do not load script via <script src="" as it will be freed when the window is closed
! 		Components.utils.import("resource://minion/mpmUtils.js");
  	]]>
  	</script>
  	
--- 10,16 ----
  	<script>
  	<![CDATA[
  	// do not load script via <script src="" as it will be freed when the window is closed
! 		Components.utils.import("chrome://minion/content/mpmUtils.js");
  	]]>
  	</script>
  	
diff -c -r -N minion.orig//chrome/content/test.js minion.patched//chrome/content/test.js
*** minion.orig//chrome/content/test.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/test.js	2012-03-30 22:47:24.257122024 +0200
***************
*** 0 ****
--- 1,22 ----
+ /**
+  * Music Player Minion Copyright 2008, Chris Seickel
+  *
+  * This program is free software; you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free Software
+  * Foundation; either version 2 of the License, or (at your option) any later
+  * version.
+  *
+  * This program is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+  * details.
+  *
+  * You should have received a copy of the GNU General Public License along with
+  * this program; if not, write to the Free Software Foundation, Inc., 51
+  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  */
+ var EXPORTED_SYMBOLS = ["niko"];
+ 
+ var niko = {niko: "cool"};
+ 
+ var dummy = "dummy";
\ No newline at end of file
diff -c -r -N minion.orig//chrome/content/trees.js minion.patched//chrome/content/trees.js
*** minion.orig//chrome/content/trees.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//chrome/content/trees.js	2012-03-30 22:54:41.065100790 +0200
***************
*** 0 ****
--- 1,466 ----
+ /**    Music Player Minion  Copyright 2008, Chris Seickel
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ */
+ 
+ Components.utils.import("chrome://minion/content/mpmUtils.js");
+ EXPORTED_SYMBOLS = ["arrayView", "playlistView", "folderView"]
+ 
+ 
+ function customTreeView () {
+     this.getRowCount = function() {return this.rs.length},
+     this.rs = []
+     this.db = []
+     this.treeBox = null
+     this.rowCount = 0
+     this.get = function (row) {return this.rs[row]}
+     this.canDrop = function (index, orientation ) {return false}
+     this.cycleCell = function (row, col ) {}
+     this.cycleHeader = function (col ) {}
+     this.drop = function (row, orientation ) {}
+     this.getCellProperties = function (row, col, props ) {
+         try {
+             var item = nsMPM.Nz(this.get(row))
+             if (item) {
+                 var t = item.type
+                 var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
+ 
+                 props.AppendElement(aserv.getAtom(col.id))
+                 if (t == 'directory' && nsMPM.mpd.updating_db) {
+                     props.AppendElement(aserv.getAtom(col.id + "_updating"))
+                 }
+                 else {
+                     props.AppendElement(aserv.getAtom(col.id + "_" + t))
+                     if (nsMPM.mpd.song && nsMPM.Nz(item.Pos, -1) == nsMPM.mpd.song) {
+                         if (col.id == 'Title' && nsMPM.mpd.state != 'stop') {
+                             props.AppendElement(aserv.getAtom(nsMPM.mpd.state + "_currentsong"))
+                         }
+                         props.AppendElement(aserv.getAtom("currentsong"))
+                     }
+                 }
+                 aserv = null
+             }
+         }
+         catch (e) {
+             nsMPM.debug(e)
+             nsMPM.debug(item)
+         }
+     }
+     this.getCellText = function(R, C){
+         var item = this.get(R)
+         if (!nsMPM.Nz(item)) return "";
+         switch (C.id) {
+             case "Pos":
+                 if (item.type != 'file') return ""
+                 var p = item.Pos
+                 if (!p) p = nsMPM.Nz(nsMPM.mpd.pl_lookup[item.file])
+                 return (p) ? (parseInt(p) + 1) + "." : "";
+                 break;
+             case "Time":
+                 return (item.Time) ? nsMPM.hmsFromSec(item.Time) : "";
+                 break;
+             default:
+                 return (item[C.id]);
+                 break;
+         }
+ 	return "";
+     }
+     this.getCellValue = function (row, col ) {return this.rs[row]}
+     this.getColumnProperties = function (col, properties ) {}
+     this.getImageSrc  = function (row, col ) {return ''}
+     this.getLevel = function  (index ) {return 0}
+     this.getParentIndex  = function (rowIndex ) {return -1}
+     this.getProgressMode  = function (row, col ) {return 3}
+     this.getRowProperties = function(index, properties){
+         try {
+             var item = this.get(index)
+             var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
+             props.AppendElement(aserv.getAtom(item.type))
+             aserv = null
+         }
+         catch (e) {
+         }
+     }
+     this.hasNextSibling = function (rowIndex, afterIndex ) {return true}
+     this.isContainer  = function (index ) {return false}
+     this.isContainerEmpty  = function (index ) {return false}
+     this.isContainerOpen  = function (index ) {return false}
+     this.isEditable  = function (row, col ) {return false}
+     this.isSelectable  = function (row, col ) {return false}
+     this.isSeparator  = function (index ) {return false}
+     this.isSorted  = function ( ) {return false}
+     this.performAction  = function (action ) {}
+     this.performActionOnCell  = function (action, row, col ) {}
+     this.performActionOnRow  = function (action, row ) {}
+     this.selectionChanged  = function ( ) {}
+     this.setCellText  = function (row, col, value ) {}
+     this.setCellValue  = function (row, col, value ) {}
+     this.setTree  = function ( tree ) {
+         this.treeBox = tree
+     }
+     this.toggleOpenState  = function (index ) {}
+ }
+ 
+ 
+ function arrayView(dbArray) {
+     this.rowCount = dbArray.length
+     this.rs = dbArray
+ 	this.getCounts = function () {
+ 		var files = [x for each (x in dbArray) if (x.type=='file')]
+ 		var time = 0
+ 		for each (f in files) {time += Math.parseInt(f.Time)}
+ 		var text = f.length + " "+nsMPM.translateService.GetStringFromName("tracks")+", " + nsMPM.prettyTime(time)
+ 	}
+ }
+ arrayView.prototype = new customTreeView
+ 
+ function playlistView(){
+     this.getPointer = function (idx) {
+         return {
+             type: 'pointer',
+             index: idx,
+             Title: 'Loading...',
+             pointer: "loading...",
+             isContainer: false,
+             isOpen: false
+         }
+     }
+     this.load = function (db, expanded){
+         if (!nsMPM.Nz(expanded)) {
+             var rc = db.length
+             var rs = new Array()
+             rs.length = rc
+             if (rc) {
+                 var n = rc
+                 do {
+                     var i = rc - n
+                     rs[i] = this.getPointer(i)
+ 
+                 }
+                 while (--n)
+             }
+         }
+         else {
+             var rc = db.length * 3
+             var rs = new Array()
+             rs.length = rc
+             if (rc) {
+                 var n = rc
+                 var idx = 0
+                 do {
+                     rs[rc - n] = this.getPointer(idx)
+                     rs[rc - n].isOpen = true
+                     --n
+                     rs[rc - n] = {
+                         index: idx,
+                         type: 'Album',
+                         Prefix: nsMPM.translateService.GetStringFromName("from")+" ",
+                         isContainer: false
+                     }
+                     --n
+                     rs[rc - n] = {
+                         index: idx,
+                         type: 'Artist',
+                         Prefix: nsMPM.translateService.GetStringFromName("by")+" ",
+                         isContainer: false
+                     }
+                     idx++
+                 }
+                 while (--n)
+             }
+         }
+         if (this.treeBox) {
+             var chg = rs.length-this.rs.length
+             var n = (chg < 0) ? 1 : this.rs.length
+             this.treeBox.rowCountChanged(n-1, chg)
+             this.treeBox.invalidate()
+             this.treeBox.scrollToRow(0)
+         }
+         this.db = db;
+         this.rs = rs;
+         this.rowCount = this.rs.length;
+     }
+     this.addItem = function (idx, expanded) {
+         var i = this.rs.length
+         var nw = this.getPointer(idx)
+         this.rs[i] = nw
+         if (expanded) {
+             this.rs[i].isOpen = true
+             this.rs[i+1] = {
+                 index: idx,
+                 type: 'Album',
+                 Prefix: nsMPM.translateService.GetStringFromName("from")+" ",
+                 isContainer: false
+             }
+             this.rs[i+2] = {
+                 index: idx,
+                 type: 'Artist',
+                 Prefix: nsMPM.translateService.GetStringFromName("by")+" ",
+                 isContainer: false
+             }
+             this.treeBox.rowCountChanged(i-1, 3)
+         }
+         else {
+             this.treeBox.rowCountChanged(i-1, 1)
+         }
+     }
+     this.removeItems = function (count) {
+         var n = this.rs.length
+         for (var i = 0; i < count; i++) {
+             --n
+             if (n > 0) {
+                 if (!this.isContainer(n)) {
+                     var n = this.getParentIndex(n)
+                 }
+             }
+             else {
+                 n = 0
+                 i = count
+             }
+         }
+         this.treeBox.rowCountChanged(n-1, n-this.rs.length)
+         this.rs.length = n
+     }
+     this.get = function (row) {
+         var cur = nsMPM.Nz(this.rs[row])
+         if (!cur) {
+             //this.treeBox.rowCountChanged(row, -1)
+             return {type: 'unknown', pos: null, time: null, Title: 'ERROR!'}
+         }
+         if (cur.type == 'pointer') {
+             return nsMPM.Nz(this.db[cur.index], cur)
+         }
+         else {
+             var item = nsMPM.Nz(this.db[cur.index], cur)
+             return {
+                 type: cur.type,
+                 index: cur.index,
+                 time: null,
+                 pos: null,
+                 Title: cur.Prefix+item[cur.type]
+             }
+         }
+     }
+     this.getPointer = function (idx) {
+         return {
+             type: 'pointer',
+             index: idx,
+             Title: 'Loading...',
+             pointer: "loading...",
+             isContainer: true,
+             isOpen: false
+         }
+     }
+     this.isContainerOpen = function(row){
+         return this.rs[row].isOpen
+     }
+     this.isContainer = function(row){
+         return (this.rs[row].isContainer)
+     }
+     this.getParentIndex = function(idx){
+         if (this.rs[idx].isContainer) return -1
+         do {
+             --idx
+         } while (!this.rs[idx].isContainer && idx > -1)
+         return idx
+     }
+     this.getLevel = function(row){
+         try {
+             return (this.rs[row].isContainer) ? 0 : 1
+         }
+         catch (e) {
+             nsMPM.debug(e)
+             return 0
+         }
+     }
+     this.hasNextSibling = function(row, afterIndex){
+         var item = this.rs[row]
+         var after = this.rs[afterIndex]
+         if (item.type == 'pointer') {
+             return (after.type == 'pointer')
+         }
+         return !(after.type == 'pointer')
+     }
+     this.toggleOpenState = function(row){
+         try {
+             if (this.rs[row].isOpen) {
+                 this.rs[row].isOpen = false
+                 this.rs.splice(parseInt(row) + 1, 2)
+                 this.treeBox.rowCountChanged(row + 1, -2)
+             }
+             else {
+                 var item = this.get(row)
+                 var art = {
+                     index: item.Pos,
+                     type: 'Artist',
+                     Prefix: nsMPM.translateService.GetStringFromName("by")+" ",
+                     isContainer: false
+                 }
+                 var alb = {
+                     index: item.Pos,
+                     type: 'Album',
+                     Prefix: nsMPM.translateService.GetStringFromName("from")+" ",
+                     isContainer: false
+                 }
+                 this.rs[row].isOpen = true
+                 this.rs.splice(row+1, 0, alb, art)
+                 this.treeBox.rowCountChanged(row, 2)
+                 //this.rowCount = this.rs.length
+             }
+         }
+         catch (e) {
+             nsMPM.debug(e)
+         }
+     }
+     this.getRowProperties = function(row, props){
+         try {
+             var item = this.rs[row]
+             if (item.type != 'unknown') {
+                 var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
+                 props.AppendElement(aserv.getAtom(item.type))
+                 var P = (parseInt(item.index) % 2) ? 'odd' : 'even'
+                 var R = (row % 2) ? 'odd' : 'even'
+                 if (P != R) {
+                     props.RemoveElement(aserv.getAtom(R))
+                     props.AppendElement(aserv.getAtom(P))
+                 }
+                 aserv = null
+             }
+         }
+         catch (e) {
+         }
+     }
+ }
+ playlistView.prototype = new customTreeView
+ 
+ 
+ function folderView(dbArray, rsArray) {
+     var rs = (nsMPM.Nz(rsArray))
+     if (!rs) rs = [x for each (x in dbArray) if (x.level == 0)].sort()
+     var view = {
+         db: dbArray,
+         rs: rs,
+         treeBox: null,
+         selection: null,
+         get rowCount () {return this.rs.length},
+         getLevel: function  (index ) {
+             return this.rs[index].level
+         },
+         getParentIndex : function (rowIndex ) {
+             var parent = this.rs[rowIndex].parent
+             if (parent == "") return -1
+             for (var idx=rowIndex-1;idx>0;idx--) {
+                 if (this.rs[idx].name == parent) return idx;
+             }
+             return -1
+         },
+         hasNextSibling: function (idx, after) {
+             var thisLevel = this.getLevel(idx);
+             for (var t = after + 1; t < this.rs.length; t++) {
+                 var nextLevel = this.getLevel(t)
+                 if (nextLevel == thisLevel) return true;
+                 else if (nextLevel < thisLevel) return false;
+             }
+ 			return false;
+         },
+         isContainer: function (index ) {
+             return true
+         },
+         isContainerEmpty : function (index ) {
+             return (this.rs[index].children < 1)
+         },
+         isContainerOpen : function (index ) {
+             if (index+1 >= this.rowCount) return false
+             return (this.rs[index+1].level > this.rs[index].level)
+         },
+ 
+         toggleOpenState : function (index ) {
+             var leaf = this.rs[index]
+             if (this.isContainerOpen(index)) {
+         var i = 1
+         while (this.rs[index + i].level > leaf.level) {i++}
+         --i
+                 this.rs.splice(index+1, i)
+                 this.treeBox.rowCountChanged(index + 1, -i)
+             }
+             else {
+                 var children = [x for each (x in this.db) if (x.parent == leaf.name)]
+                 this.rs = this.rs.slice(0, index+1).concat(children, this.rs.slice(index+1))
+                 this.treeBox.rowCountChanged(index+1, children.length)
+             }
+         },
+         canDrop: function (index, orientation ) {return false},
+         cycleCell: function (row, col ) {},
+         cycleHeader: function (col ) {},
+         drop: function (row, orientation ) {},
+         getCellProperties: function (row, col, props ) {
+             try {
+                 var item = this.rs[row]
+                 var t = item.type
+                 var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
+ 
+                 props.AppendElement(aserv.getAtom(col.id))
+                 if (t == 'directory' && nsMPM.mpd.updating_db) {
+                     props.AppendElement(aserv.getAtom(col.id + "_updating"))
+                 }
+                 else {
+                     props.AppendElement(aserv.getAtom(col.id + "_" + t))
+                     if (item.name == nsMPM.mpd.file) {
+                         if (col.id == 'Title' && nsMPM.mpd.state != 'stop') {
+                             props.AppendElement(aserv.getAtom(nsMPM.mpd.state + "_currentsong"))
+                         }
+                         props.AppendElement(aserv.getAtom("currentsong"))
+                     }
+                 }
+                 aserv = null
+             }
+             catch (e) {
+                 nsMPM.debug(e)
+             }
+         },
+         getCellText: function(R, C){
+             return this.rs[R].Title
+         },
+         getCellValue: function (row, col ) {return this.rs[row]},
+         getColumnProperties: function (col, properties ) {},
+         getImageSrc : function (row, col ) {return ''},
+         getProgressMode : function (row, col ) {return 3},
+         getRowProperties: function(index, properties){
+             try {
+                 var item = this.rs[index]
+                 var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
+                 props.AppendElement(aserv.getAtom(item.type))
+                 aserv = null
+             }
+             catch (e) {
+             }
+         },
+         isEditable : function (row, col ) {return false},
+         isSelectable : function (row, col ) {return false},
+         isSeparator : function (index ) {return false},
+         isSorted : function ( ) {return false},
+         performAction : function (action ) {},
+         performActionOnCell : function (action, row, col ) {},
+         performActionOnRow : function (action, row ) {},
+         selectionChanged : function ( ) {},
+         setCellText : function (row, col, value ) {},
+         setCellValue : function (row, col, value ) {},
+         setTree : function ( tree ) {
+             this.treeBox = tree
+         }
+     }
+     return view
+ }
diff -c -r -N minion.orig//chrome/content/upgrade.xul minion.patched//chrome/content/upgrade.xul
*** minion.orig//chrome/content/upgrade.xul	2012-03-30 23:07:40.153062918 +0200
--- minion.patched//chrome/content/upgrade.xul	2012-03-30 22:58:27.393089788 +0200
***************
*** 13,19 ****
  
  	<script>
  	<![CDATA[
!         Components.utils.import("resource://minion/mpmUtils.js");
  	]]>	
  	</script>
  	<script type="application/x-javascript" src="chrome://global/content/contentAreaUtils.js"/>
--- 13,19 ----
  
  	<script>
  	<![CDATA[
!         Components.utils.import("chrome://minion/content/mpmUtils.js");
  	]]>	
  	</script>
  	<script type="application/x-javascript" src="chrome://global/content/contentAreaUtils.js"/>
diff -c -r -N minion.orig//chrome/resource/about.js minion.patched//chrome/resource/about.js
*** minion.orig//chrome/resource/about.js	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/resource/about.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,132 ****
- Components.utils.import("resource://minion/mpmUtils.js");
- 
- function init() {
-     var rdfs = Components.classes['@mozilla.org/rdf/rdf-service;1'].
-                           getService(Components.interfaces.nsIRDFService);
-     var extension = rdfs.GetResource('urn:mozilla:item:Music_Player_Minion@code.google.com');
-     var gExtensionDB = Components.classes['@mozilla.org/extensions/manager;1'].
-                        getService(Components.interfaces.nsIExtensionManager).
-                        QueryInterface(Components.interfaces.nsIExtensionManager).
-                        datasource;
- 
-     var extensionsStrings = document.getElementById('extensionsStrings');
- 
-     // Name
-     var nameArc = rdfs.GetResource(EM_NS('name'));
-     var name = gExtensionDB.GetTarget(extension, nameArc, true);
-     name = name.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
- 
-     // Version
-     var versionArc = rdfs.GetResource(EM_NS('version'));
-     var version = gExtensionDB.GetTarget(extension, versionArc, true);
-     version = version.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
- 
-     // Description
-     var descriptionArc = rdfs.GetResource(EM_NS('description'));
-     var description = gExtensionDB.GetTarget(extension, descriptionArc, true);
-     if (description)
-       description = description.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
- 
-     // Home Page URL
-     var homepageArc = rdfs.GetResource(EM_NS('homepageURL'));
-     var homepage = gExtensionDB.GetTarget(extension, homepageArc, true);
-     if (homepage) {
-         homepage = homepage.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
-         // only allow http(s) homepages
-         var scheme = '';
-         var uri = null;
-         try {
-             uri = makeURI(homepage);
-             scheme = uri.scheme;
-         }
-         catch (ex) {}
- 
-         if (uri && (scheme == 'http' || scheme == 'https'))
-             homepage = uri.spec;
-         else
-             homepage = null;
-     }
- 
-     // Creator
-     var creatorArc = rdfs.GetResource(EM_NS('creator'));
-     var creator = gExtensionDB.GetTarget(extension, creatorArc, true);
-     if (creator)
-         creator = creator.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
- 
-     document.title = extensionsStrings.getFormattedString('aboutWindowTitle', [name]);
-     var extensionName = document.getElementById('extensionName');
-     extensionName.setAttribute('value', name);
-     var extensionVersion = document.getElementById('extensionVersion');
-     extensionVersion.setAttribute('value', version);
- 
-     var extensionDescription = document.getElementById('extensionDescription');
-     extensionDescription.appendChild(document.createTextNode(description));
- 
-     var extensionCreator = document.getElementById('extensionCreator');
-     extensionCreator.setAttribute('value', creator);
- 
-     var extensionHomepage = document.getElementById('extensionHomepage');
-     if (homepage) {
-         extensionHomepage.setAttribute('homepageURL', homepage);
-         extensionHomepage.setAttribute('tooltiptext', homepage);
-         extensionHomepage.blur();
-     }
-     else
-         extensionHomepage.hidden = true;
- 
-     // Translators
-     var translatorArc = rdfs.GetResource(EM_NS('translator'));
-     var targets = gExtensionDB.GetTargets(extension, translatorArc, true);
-     if (!targets.hasMoreElements()) {
-         document.getElementById('extensionTranslators').hidden = true;
-     } else {
-         var i = 0;
-         var rows = document.getElementById('translatorsRows');
-         while (targets.hasMoreElements()) {
-             var literalValue = targets.getNext().
-                                QueryInterface(Components.interfaces.nsIRDFLiteral).
-                                Value;
- 
-             if (i / 2 == Math.floor(i / 2)) {
-                 var row = document.createElement('row');
-                 rows.appendChild(row);
-             }
- 
-             var label = document.createElement('label');
-             label.setAttribute('value', literalValue);
-             label.setAttribute('class', 'contributor');
-             row.appendChild(label);
-             i++;
-         }
-     }
- 
-     // Contributors
-     var node = document.getElementById('contributorsBox');
-     var arc = rdfs.GetResource(EM_NS('contributor'));
-     var targets = gExtensionDB.GetTargets(extension, arc, true);
-     if (!targets.hasMoreElements())
-         document.getElementById('extensionContributors').hidden = true;
-     else {
-         while (targets.hasMoreElements()) {
-             var literalValue = targets.getNext().
-                                QueryInterface(Components.interfaces.nsIRDFLiteral).
-                                Value;
-             var label = document.createElement('label');
-             label.setAttribute('value', literalValue);
-             label.setAttribute('class', 'contributor');
-             node.appendChild(label);
-         }
-     }
- 
-     var acceptButton = document.documentElement.getButton('accept');
-     acceptButton.label = extensionsStrings.getString('aboutWindowCloseButton');
- }
- 
- function EM_NS(aProperty) {
-     return 'http://www.mozilla.org/2004/em-rdf#' + aProperty;
- }
- 
- function loadHomepage(aEvent) {
-     window.close();
-     window.opener.openURL(aEvent.target.getAttribute('homepageURL'));
- }
--- 0 ----
diff -c -r -N minion.orig//chrome/resource/io.js minion.patched//chrome/resource/io.js
*** minion.orig//chrome/resource/io.js	2012-03-30 23:07:40.145062918 +0200
--- minion.patched//chrome/resource/io.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,319 ****
- /////////////////////////////////////////////////
- /////////////////////////////////////////////////
- //
- // Basic JavaScript File and Directory IO module
- // By: MonkeeSage, v0.1
- //
- /////////////////////////////////////////////////
- /////////////////////////////////////////////////
- let EXPORTED_SYMBOLS = ["FileIO", "DirIO"]
- /////////////////////////////////////////////////
- // Basic file IO object based on Mozilla source
- // code post at forums.mozillazine.org
- /////////////////////////////////////////////////
- 
- // Example use:
- // var fileIn = FileIO.open('/test.txt');
- // if (fileIn.exists()) {
- // 	var fileOut = FileIO.open('/copy of test.txt');
- // 	var str = FileIO.read(fileIn);
- // 	var rv = FileIO.write(fileOut, str);
- // 	alert('File write: ' + rv);
- // 	rv = FileIO.write(fileOut, str, 'a');
- // 	alert('File append: ' + rv);
- // 	rv = FileIO.unlink(fileOut);
- // 	alert('File unlink: ' + rv);
- // }
- 
- var FileIO = {
- 
-     localfileCID  : '@mozilla.org/file/local;1',
-     localfileIID  : Components.interfaces.nsILocalFile,
- 
-     finstreamCID  : '@mozilla.org/network/file-input-stream;1',
-     finstreamIID  : Components.interfaces.nsIFileInputStream,
- 
-     foutstreamCID : '@mozilla.org/network/file-output-stream;1',
-     foutstreamIID : Components.interfaces.nsIFileOutputStream,
- 
-     sinstreamCID  : '@mozilla.org/scriptableinputstream;1',
-     sinstreamIID  : Components.interfaces.nsIScriptableInputStream,
- 
-     suniconvCID   : '@mozilla.org/intl/scriptableunicodeconverter',
-     suniconvIID   : Components.interfaces.nsIScriptableUnicodeConverter,
- 
-     open   : function(path) {
-         try {
-             var file = Components.classes[this.localfileCID]
-                             .createInstance(this.localfileIID);
-             file.initWithPath(path);
-             return file;
-         }
-         catch(e) {
-             return false;
-         }
-     },
- 
-     read   : function(file, charset) {
-         try {
-             var data     = new String();
-             var fiStream = Components.classes[this.finstreamCID]
-                                 .createInstance(this.finstreamIID);
-             var siStream = Components.classes[this.sinstreamCID]
-                                 .createInstance(this.sinstreamIID);
-             fiStream.init(file, 1, 0, false);
-             siStream.init(fiStream);
-             data += siStream.read(-1);
-             siStream.close();
-             fiStream.close();
-             if (charset) {
-                 data = this.toUnicode(charset, data);
-             }
-             return data;
-         }
-         catch(e) {
-             return false;
-         }
-     },
- 
-     write  : function(file, data, mode, charset) {
-         try {
-             var foStream = Components.classes[this.foutstreamCID]
-                                 .createInstance(this.foutstreamIID);
-             if (charset) {
-                 data = this.fromUnicode(charset, data);
-             }
-             var flags = 0x02 | 0x08 | 0x20; // wronly | create | truncate
-             if (mode == 'a') {
-                 flags = 0x02 | 0x10; // wronly | append
-             }
-             foStream.init(file, flags, 0664, 0);
-             foStream.write(data, data.length);
-             // foStream.flush();
-             foStream.close();
-             return true;
-         }
-         catch(e) {
-             return false;
-         }
-     },
- 
-     create : function(file) {
-         try {
-             file.create(0x00, 0664);
-             return true;
-         }
-         catch(e) {
-             return e.description;
-         }
-     },
- 
-     unlink : function(file) {
-         try {
-             file.remove(false);
-             return true;
-         }
-         catch(e) {
-             return false;
-         }
-     },
- 
-     path   : function(file) {
-         try {
-             return 'file:///' + file.path.replace(/\\/g, '\/')
-                         .replace(/^\s*\/?/, '').replace(/\ /g, '%20');
-         }
-         catch(e) {
-             return false;
-         }
-     },
- 
-     toUnicode   : function(charset, data) {
-         try{
-             var uniConv = Components.classes[this.suniconvCID]
-                                 .createInstance(this.suniconvIID);
-             uniConv.charset = charset;
-             data = uniConv.ConvertToUnicode(data);
-         }
-         catch(e) {
-             // foobar!
-         }
-         return data;
-     },
- 
-     fromUnicode : function(charset, data) {
-         try {
-             var uniConv = Components.classes[this.suniconvCID]
-                                 .createInstance(this.suniconvIID);
-             uniConv.charset = charset;
-             data = uniConv.ConvertFromUnicode(data);
-             // data += uniConv.Finish();
-         }
-         catch(e) {
-             // foobar!
-         }
-         return data;
-     }
- 
- }
- 
- 
- /////////////////////////////////////////////////
- // Basic Directory IO object based on JSLib
- // source code found at jslib.mozdev.org
- /////////////////////////////////////////////////
- 
- // Example use:
- // var dir = DirIO.open('/test');
- // if (dir.exists()) {
- // 	alert(DirIO.path(dir));
- // 	var arr = DirIO.read(dir, true), i;
- // 	if (arr) {
- // 		for (i = 0; i < arr.length; ++i) {
- // 			alert(arr[i].path);
- // 		}
- // 	}
- // }
- // else {
- // 	var rv = DirIO.create(dir);
- // 	alert('Directory create: ' + rv);
- // }
- 
- // ---------------------------------------------
- // ----------------- Nota Bene -----------------
- // ---------------------------------------------
- // Some possible types for get are:
- // 	'ProfD'				= profile
- // 	'DefProfRt'			= user (e.g., /root/.mozilla)
- // 	'UChrm'				= %profile%/chrome
- // 	'DefRt'				= installation
- // 	'PrfDef'				= %installation%/defaults/pref
- // 	'ProfDefNoLoc'		= %installation%/defaults/profile
- // 	'APlugns'			= %installation%/plugins
- // 	'AChrom'				= %installation%/chrome
- // 	'ComsD'				= %installation%/components
- // 	'CurProcD'			= installation (usually)
- // 	'Home'				= OS root (e.g., /root)
- // 	'TmpD'				= OS tmp (e.g., /tmp)
- 
- var DirIO = {
- 
-     sep        : '/',
- 
-     dirservCID : '@mozilla.org/file/directory_service;1',
- 
-     propsIID   : Components.interfaces.nsIProperties,
- 
-     fileIID    : Components.interfaces.nsIFile,
- 
-     get    : function(type) {
-         try {
-             var dir = Components.classes[this.dirservCID]
-                             .createInstance(this.propsIID)
-                             .get(type, this.fileIID);
-             return dir;
-         }
-         catch(e) {
-             return false;
-         }
-     },
- 
-     open   : function(path) {
-         return FileIO.open(path);
-     },
- 
-     create : function(dir) {
-         try {
-             dir.create(0x01, 0640);
-             return true;
-         }
-         catch(e) {
-             return false;
-         }
-     },
- 
-     read   : function(dir, recursive) {
-         var list = new Array();
-         try {
-             if (dir.isDirectory()) {
-                 if (recursive == null) {
-                     recursive = false;
-                 }
-                 var files = dir.directoryEntries;
-                 list = this._read(files, recursive);
-             }
-         }
-         catch(e) {
-             // foobar!
-         }
-         return list;
-     },
- 
-     _read  : function(dirEntry, recursive) {
-         var list = new Array();
-         try {
-             while (dirEntry.hasMoreElements()) {
-                 list.push(dirEntry.getNext()
-                                 .QueryInterface(FileIO.localfileIID));
-             }
-             if (recursive) {
-                 var list2 = new Array();
-                 for (var i = 0; i < list.length; ++i) {
-                     if (list[i].isDirectory()) {
-                         files = list[i].directoryEntries;
-                         list2 = this._read(files, recursive);
-                     }
-                 }
-                 for (i = 0; i < list2.length; ++i) {
-                     list.push(list2[i]);
-                 }
-             }
-         }
-         catch(e) {
-            // foobar!
-         }
-         return list;
-     },
- 
-     unlink : function(dir, recursive) {
-         try {
-             if (recursive == null) {
-                 recursive = false;
-             }
-             dir.remove(recursive);
-             return true;
-         }
-         catch(e) {
-             return false;
-         }
-     },
- 
-     path   : function (dir) {
-         return FileIO.path(dir);
-     },
- 
-     split  : function(str, join) {
-         var arr = str.split(/\/|\\/), i;
-         str = new String();
-         for (i = 0; i < arr.length; ++i) {
-             str += arr[i] + ((i != arr.length - 1) ?
-                                     join : '');
-         }
-         return str;
-     },
- 
-     join   : function(str, split) {
-         var arr = str.split(split), i;
-         str = new String();
-         for (i = 0; i < arr.length; ++i) {
-             str += arr[i] + ((i != arr.length - 1) ?
-                                     this.sep : '');
-         }
-         return str;
-     }
- 
- }
- 
- /* if (navigator.platform.toLowerCase().indexOf('win') > -1) {
-     DirIO.sep = '\\';
- } */
--- 0 ----
diff -c -r -N minion.orig//chrome/resource/JSON.js minion.patched//chrome/resource/JSON.js
*** minion.orig//chrome/resource/JSON.js	2012-03-30 23:07:40.145062918 +0200
--- minion.patched//chrome/resource/JSON.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,83 ****
- /* ***** BEGIN LICENSE BLOCK *****
-  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-  *
-  * The contents of this file are subject to the Mozilla Public License Version
-  * 1.1 (the "License"); you may not use this file except in compliance with
-  * the License. You may obtain a copy of the License at
-  * http://www.mozilla.org/MPL/
-  *
-  * Software distributed under the License is distributed on an "AS IS" basis,
-  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-  * for the specific language governing rights and limitations under the
-  * License.
-  *
-  * The Original Code is Personas.
-  *
-  * The Initial Developer of the Original Code is Mozilla.
-  * Portions created by the Initial Developer are Copyright (C) 2008
-  * the Initial Developer. All Rights Reserved.
-  *
-  * Contributor(s):
-  *   Myk Melez <myk@mozilla.org>
-  *
-  * Alternatively, the contents of this file may be used under the terms of
-  * either the GNU General Public License Version 2 or later (the "GPL"), or
-  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-  * in which case the provisions of the GPL or the LGPL are applicable instead
-  * of those above. If you wish to allow use of your version of this file only
-  * under the terms of either the GPL or the LGPL, and not to allow others to
-  * use your version of this file under the terms of the MPL, indicate your
-  * decision by deleting the provisions above and replace them with the notice
-  * and other provisions required by the GPL or the LGPL. If you do not delete
-  * the provisions above, a recipient may use your version of this file under
-  * the terms of any one of the MPL, the GPL or the LGPL.
-  *
-  * ***** END LICENSE BLOCK ***** */
- 
- /**
-  * This module wraps the incompatible Gecko 1.9.0 (Firefox 3.0) and Gecko 1.9.1
-  * (Firefox 3.5) JSON APIs, presenting the Gecko 1.9.1 API on both versions,
-  * for extensions that support multiple versions of Gecko-based applications.
-  *
-  * Import this module into your extension to parse and stringify JSON in both
-  * Firefox 3.0 and 3.5 (and other Gecko-based applications, like Thunderbird)
-  * without checking the application's version each time.
-  *
-  * Note: don't import this into the global namespace!  If you do, you'll hork
-  * native application code that expects the Gecko 1.9.0 API.  Instead, import it
-  * into your own object like this:
-  *
-  *   let MyExtension = {
-  *     JSON: null,
-  *     ...
-  *   };
-  *   Components.utils.import("chrome://myextension/modules/JSON.js", MyExtension);
-  *   // Now MyExtension.JSON is an object implementing the Gecko 1.9.1 JSON API.
-  *
-  * The Gecko 1.9.1 (Firefox 3.5) JSON API is documented in the article:
-  *   https://developer.mozilla.org/En/Using_JSON_in_Firefox
-  */
- 
- let EXPORTED_SYMBOLS = ["JSON"];
- 
- const Cc = Components.classes;
- const Ci = Components.interfaces;
- const Cr = Components.results;
- const Cu = Components.utils;
- 
- let appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
- 
- // Iceweasel 3.0 has a bug where it reports its platform version as 1.9 instead
- // of 1.9.0.n; we work around the bug by checking for 1.9 in addition to 1.9.0.n
- // and wrapping the JSON API in both cases.
- if (appInfo.platformVersion.indexOf("1.9.0") == 0 ||
-     appInfo.platformVersion == "1.9") {
-   // Declare JSON with |var| so it'll be defined outside the enclosing
-   // conditional block.
-   var JSON = {
-       JSON: null,
-       parse: function(jsonString) { return this.JSON.fromString(jsonString) },
-       stringify: function(jsObject) { return this.JSON.toString(jsObject) }
-   }
-   Cu.import("resource://gre/modules/JSON.jsm", JSON);
- }
--- 0 ----
diff -c -r -N minion.orig//chrome/resource/mpd.js minion.patched//chrome/resource/mpd.js
*** minion.orig//chrome/resource/mpd.js	2012-03-30 23:07:40.145062918 +0200
--- minion.patched//chrome/resource/mpd.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,1276 ****
- /**
-  * Music Player Minion Copyright 2008, Chris Seickel
-  *
-  * This program is free software; you can redistribute it and/or modify it under
-  * the terms of the GNU General Public License as published by the Free Software
-  * Foundation; either version 2 of the License, or (at your option) any later
-  * version.
-  *
-  * This program is distributed in the hope that it will be useful, but WITHOUT
-  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-  * details.
-  *
-  * You should have received a copy of the GNU General Public License along with
-  * this program; if not, write to the Free Software Foundation, Inc., 51
-  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-  */
- Components.utils.import("resource://minion/mpmUtils.js");
- 
- let EXPORTED_SYMBOLS = ["dbQuery", "mpd"]
- 
- var lfId = nsMPM.prefs.get("lyricsfly_id","8890a06f973057f4b")
- 
- const NOSRV_STATUS = 2152398861
- const LOSTC_STATUS = 2152398868
- 
- var default_servers = [["localhost", "localhost:6600:"]];
- 
- var mpd = {
-     _host : null,
-     _port : null,
-     _password : null,
-     
-     // Output of status
-     volume : null,
-     repeat : null,
-     random : null,
-     playlistlength : 0,
-     playlist : 0,
-     xfade : null,
-     state : null,
-     song : null,
-     songid : null,
-     time : null,
-     bitrate : null,
-     updating_db : null,
-     
-     // Output of currentsong
-     file : null,
-     Time : null,
-     Artist : null,
-     Title : null,
-     sbTitle : null,
-     Album : null,
-     Track : null,
-     Date : null,
-     Genre : null,
-     Composer : null,
-     currentsong : {}, // All values as object. Observe this if you need
-                         // multiple properties.
-     
-     db_update : null,
-     sec_ticks : 0,
-     sec_synced : false,
-     update_interval : nsMPM.prefs.get("update_interval", 200),
-     adaptive_interval : nsMPM.prefs.get("adaptive_interval", true),
-     playlistname : nsMPM.translateService.GetStringFromName("new_playlist"),
-     
-     // Playlist contents and total playtime
-     plinfo : [],
-     pltime : 0,
-     prettytime: '',
-     pl_lookup : {},
-     
-     // Connection state information
-     greeting : nsMPM.translateService.GetStringFromName('not_connected'),
-     last_command : '',
-     lastResponse : '',
-     _idle : false,
-     _doStatus : true,
-     _timer : null,
-     _cmdQueue : [],
-     _socket : null,
-     
-     cachedArt : [],
-     cachedDB : [],
-     servers : [["localhost", "localhost:6600:"]]
- }
- 
- mpd._checkStatus = function() {
-     nsMPM.mpd._doStatus = true
-     var tm = (nsMPM.mpd.state != 'play') ? 1500 : nsMPM.mpd.update_interval
-     if (nsMPM.mpd._timer) {
-         nsMPM.mpd._timer.cancel()
-     }
-     if (!nsMPM.mpd._socket) {
-         nsMPM.mpd._socket = socketTalker()
-     }
-     if (nsMPM.mpd._idle) {
-         nsMPM.mpd.doCmd("ping", null, true)
-     }
-     if (nsMPM.mpd._socket) {
-         var cb = {
-             notify : function(tmr) {
-                 nsMPM.mpd._checkStatus()
-             }
-         }
-         nsMPM.mpd._timer = Components.classes["@mozilla.org/timer;1"]
-                 .createInstance(Components.interfaces.nsITimer)
-         nsMPM.mpd._timer.initWithCallback(cb, tm,
-                 Components.interfaces.nsITimer.TYPE_ONE_SHOT)
-     }
- }
- 
- // Parse output from currentsong nsMPM.mpd.doCmd, internal use only.
- mpd._parseCurrentSong = function(data) {
-     // parse the incoming data into a status object
-     var obj = new Object()
-     data = data.split("\n")
-     var dl = data.length
-     var pair
-     do {
-         var sep = data[dl - 1].indexOf(": ")
-         if (sep > 0) {
-             obj[data[dl - 1].substr(0, sep)] = data[dl - 1].slice(sep + 2)
-         }
-     } while (--dl)
- 
-     // React to and alter certain values.
-     if (nsMPM.Nz(obj.file)) {
-         if (nsMPM.Nz(obj.Title, '') == '') {
-             if (nsMPM.prefs.get("guess_tags", false)) obj = nsMPM.guessTags(obj)
-             else obj.Title = obj.file.split("/").pop()
-         }
-         obj.type = 'file'
-         obj.name = obj.file
-     }
- 
-     // set currentsong values
-     nsMPM.mpd.set('Time', nsMPM.Nz(obj.Time))
-     nsMPM.mpd.set('Artist', nsMPM.Nz(obj.Artist))
-     nsMPM.mpd.set('Title', nsMPM.Nz(obj.Title))
-     nsMPM.mpd.set('sbTitle', nsMPM.Nz(obj.Title))
-     nsMPM.mpd.set('Album', nsMPM.Nz(obj.Album))
-     nsMPM.mpd.set('Track', nsMPM.Nz(obj.Track))
-     nsMPM.mpd.set('Date', nsMPM.Nz(obj.Date))
-     nsMPM.mpd.set('Genre', nsMPM.Nz(obj.Genre))
-     nsMPM.mpd.set('Composer', nsMPM.Nz(obj.Composer))
-     nsMPM.mpd.set('currentsong', obj)
-     nsMPM.mpd.set('file', nsMPM.Nz(obj.file))
- }
- 
- mpd._parseDB = function(data) {
-     data = data.split("\n")
-     var db = []
-     var dl = data.length
-     var guess = nsMPM.prefs.get("guess_tags", false)
-     if (dl > 0) {
-         var n = dl
-         do {
-             var i = dl - n
-             var sep = data[i].indexOf(": ")
-             if (sep > -1) {
-                 var fld = data[i].substr(0, sep)
-                 var val = data[i].slice(sep + 2)
-                 if (fld == 'file') {
-                     var song = {
-                         type : 'file',
-                         file : val,
-                         name : val,
-                         Track : '',
-                         Title : '',
-                         Artist : '',
-                         Album : '',
-                         Time : 0,
-                         Pos : null,
-                         Id: null
-                     };
-                     var d = data[i + 1]
-                     while (d && d.charCodeAt(0) < 97) {
-                         var sep = d.indexOf(": ")
-                         song[d.substr(0, sep)] = d.slice(sep + 2);
-                         --n;
-                         var d = data[dl - n + 1]
-                     };
-                     if (song.Title == '') {
-                         if (guess) song = nsMPM.guessTags(song)
-                         else song.Title = val.split("/").pop()
-                     }
-                     db.push(song);
-                 } else {
-                     if (fld == 'directory') {
-                         var dir = val.split("/")
-                         db.push({
-                             type : 'directory',
-                             name : val,
-                             Title : dir[dir.length - 1],
-                             file : val
-                         })
-                     } else {
-                         var x = {
-                             type : fld,
-                             name : val,
-                             Title : val
-                         }
-                         x[fld] = val
-                         db.push(x)
-                     }
-                 }
-             }
-         } while (--n)
-     }
-     return db
- }
- 
- mpd._parsePL = function(data) {
-     try {
-         nsMPM.debug("_parsePL: playlist="+mpd.playlist)
-         var db = nsMPM.mpd._parseDB(data, false)
-         if (db.length == 0) nsMPM.mpd._parseCurrentSong("")
-         if (db.length > 0) {
-             var i = db.length - 1
-             do {
-                 nsMPM.mpd.plinfo[db[i].Pos] = db[i]
-                 nsMPM.mpd.pl_lookup[db[i].file] = db[i].Pos
-             } while (i--)
-         }
-         var l = nsMPM.mpd.plinfo.length
-         var tm = 0
-         if (l > 0) {
-             var n = l
-             do {
-                 var item = nsMPM.Nz(nsMPM.mpd.plinfo[l - n])
-                 if (item)
-                     tm += parseInt(nsMPM.mpd.plinfo[l - n].Time)
-                 else {
-                     nsMPM.debug("Missing playlist item " + (l - n)
-                             + " when calculating time.")
-                     nsMPM.mpd.playlist = 0
-                 }
-             } while (--n)
-         }
-         nsMPM.mpd.set("pltime", tm)
-         nsMPM.observerService.notifyObservers(null, "plinfo", db.length)
-         nsMPM.mpd.set("playlistlength", nsMPM.mpd.playlistlength)
-         nsMPM.mpd.set("prettytime", nsMPM.prettyTime(tm))
-         if (nsMPM.mpd.playlistlength == 0) {
-             nsMPM.mpd.set("playlistname", nsMPM.translateService.GetStringFromName("new_playlist"))
-         } else {
-             if (nsMPM.mpd.playlistname == nsMPM.translateService.GetStringFromName("new_playlist")) nsMPM.mpd.guessPlaylistName()
-         }
-     } catch (e) {
-         nsMPM.debug(e);
-         nsMPM.mpd.playlist = 0
-     }
- }
- 
- // Parse output from status nsMPM.mpd.doCmd, internal use only.
- mpd._update = function(data) {
-     try {
-         // parse the incoming data into a status object
-         var obj = new Object()
-         data = data.split("\n")
-         var dl = data.length
-         var pair
-         do {
-             pair = data[dl - 1].split(": ", 2)
-             if (pair.length == 2) {
-                 obj[pair[0]] = pair[1]
-             }
-         } while (--dl)
- 
-         // React to and alter certain values.
-         var t = nsMPM.Nz(obj.time, '0:0').split(":")
-         if (obj.state == 'stop') {
-             obj.time = 0
-         } else {
-             obj.time = t[0]
-         }
- 
-         // Adaptive update intervals. Run updates at 200 ms until we are
-         // updating in sync with the time, then switch to 1000 ms.
-         if (nsMPM.mpd.state == 'play' && nsMPM.mpd.adaptive_interval) {
-             if (obj.time == nsMPM.mpd.time) {
-                 nsMPM.mpd.sec_ticks++
-             } else {
-                 if (nsMPM.mpd.update_interval == 1000) {
-                     nsMPM.mpd.sec_synced = (nsMPM.mpd.sec_ticks < 2)
-                 } else {
-                     nsMPM.mpd.sec_synced = (nsMPM.mpd.sec_ticks == 4)
-                     nsMPM.mpd.sec_ticks = 0
-                 }
-             }
-             nsMPM.mpd.update_interval = (nsMPM.mpd.sec_synced) ? 1000 : 200
-         }
- 
-         if (obj.songid != nsMPM.mpd.songid) {
-             nsMPM.mpd.doCmd("currentsong", nsMPM.mpd._parseCurrentSong, true)
-         } else {
-             CS = false
-             if (obj.song <= nsMPM.mpd.plinfo.length) {
-                 CS = nsMPM.Nz(nsMPM.mpd.plinfo[obj.song])
-                 if (CS.file.indexOf("://") > 0) {
-                     if (CS.Title != nsMPM.mpd.Title){
-                         nsMPM.mpd.doCmd("currentsong", nsMPM.mpd._parseCurrentSong, true)
-                     }
-                 }
-             }
-         }
-         nsMPM.mpd.playlist = nsMPM.Nz(nsMPM.mpd.playlist, 0)
-         if (obj.playlist != nsMPM.mpd.playlist) {
-             var l = parseInt(nsMPM.Nz(obj.playlistlength, 0))
-             if (l < nsMPM.mpd.plinfo.length && nsMPM.Nz(nsMPM.mpd.pl_lookup)) {
-                 var new_lookup = {}
-                 for (x in nsMPM.mpd.pl_lookup) {
-                     if (nsMPM.mpd.pl_lookup[x] < l) new_lookup[x] = nsMPM.mpd.pl_lookup[x]
-                 }
-                 nsMPM.mpd.pl_lookup = new_lookup
-             }
-             nsMPM.mpd.plinfo.length = l
-             var cmd = (nsMPM.mpd.playlist > 0)
-                     ? "plchanges " + nsMPM.mpd.playlist
-                     : "playlistinfo"
-             nsMPM.mpd.doCmd(cmd, nsMPM.mpd._parsePL, true)
-         }
-         nsMPM.mpd.playlist = nsMPM.Nz(obj.playlist)
-         if (nsMPM.mpd.updating_db) {
-             if (!nsMPM.Nz(obj.updating_db)) {
-                 nsMPM.mpd.set('updating_db', null)
-                 nsMPM.mpd.cachedDB = []
-             }
-         }
- 
-         // set status values
-         nsMPM.mpd.set('volume', nsMPM.Nz(obj.volume))
-         nsMPM.mpd.set('repeat', nsMPM.Nz(obj.repeat))
-         nsMPM.mpd.set('random', nsMPM.Nz(obj.random))
-         nsMPM.mpd.set('playlistlength', nsMPM.Nz(obj.playlistlength))
-         nsMPM.mpd.set('xfade', nsMPM.Nz(obj.xfade))
-         nsMPM.mpd.set('state', nsMPM.Nz(obj.state))
-         nsMPM.mpd.set('song', nsMPM.Nz(obj.song))
-         nsMPM.mpd.set('time', nsMPM.Nz(obj.time))
-         nsMPM.mpd.set('bitrate', nsMPM.Nz(obj.bitrate))
-         nsMPM.mpd.set('updating_db', nsMPM.Nz(obj.updating_db))
-         nsMPM.mpd.set('db_update', nsMPM.Nz(obj.db_update))
- 
-         nsMPM.mpd._doStatus = false
-     } catch (e) {
-         nsMPM.debug(e)
-     }
- }
- 
- mpd.addToPlaylist = function(itemArray) {
-     // Input should be an array of db objects or a single db object.
-     if (typeof(itemArray[0]) != 'object')
-         itemArray = [itemArray]
-     var l = itemArray.length
-     var cmd = "command_list_begin"
-     var hasFiles = false
-     for (var i = 0; i < l; i++) {
-         var item = itemArray[i]
-         if (item.type == 'file' || item.type == 'directory') {
-             hasFiles = true
-             cmd += '\nadd ' + nsMPM.Sz(item.name)
-         } else {
-             var q = new nsMPM.dbQuery()
-             q.type = 'file'
-             q.scope = item.type
-             q.query = item.name
-             q.callBack = function(db) {
-                 var dbl = db.length
-                 var c = "command_list_begin"
-                 for (var x = 0; x < dbl; x++) {
-                     c += '\nadd ' + nsMPM.Sz(db[x].name)
-                 }
-                 nsMPM.mpd.doCmd(c + "\ncommand_list_end")
-             }
-             q.execute()
-         }
-     }
-     if (hasFiles) {
-         hasFiles = false
-         nsMPM.mpd.doCmd(cmd + "\ncommand_list_end")
-         cmd = "command_list_begin"
-     }
- }
- // Connection methods
- mpd.connect = function() {
-     if (nsMPM.mpd._timer) {
-         nsMPM.mpd._timer.cancel()
-         nsMPM.mpd._timer = null
-     }
-     if (nsMPM.mpd._socket) {
-         nsMPM.mpd._socket.cancel()
-         nsMPM.mpd._socket = null
-     }
-     if (nsMPM.mpd._host && nsMPM.mpd._port) {
-         nsMPM.mpd.set("playlistname", nsMPM.translateService.GetStringFromName("new_playlist"))
-         nsMPM.mpd._checkStatus()
-     } else
-         nsMPM.mpd.set("lastResponse", nsMPM.translateService.GetStringFromName("server_not_selected"))
- }
- 
- mpd.force_connect = function() { let that = this; that.loadSrvPref() }
- mpd.disconnect = function() {
-     if (nsMPM.mpd._timer) {
-         nsMPM.mpd._timer.cancel()
-         nsMPM.mpd._timer = null
-     }
-     if (nsMPM.mpd._socket) {
-         nsMPM.mpd._socket.cancel()
-         nsMPM.mpd._socket = null
-     }
-     nsMPM.mpd._host = null
-     nsMPM.mpd._port = null
- }
- 
- // Talk directlty to MPD, outputData must be properly escaped and quoted.
- // callBack is optional, if left out or null and no socket is in use,
- // a single use connection will be made for this nsMPM.mpd.doCmd.
- mpd.doCmd = function(outputData, callBack, hide, priority) {
-     
-     hide = nsMPM.Nz(hide)
-     priority = nsMPM.Nz(priority)
-     if (/^rename\ |^rm\ |^save\ /m.test(outputData)) {
-         callBack = function(d) {
-             nsMPM.observerService.notifyObservers(null, 'playlists', null)
-         }
-     }
-     if (/^\s*load\s/m.test(outputData)) {
-         var name = /^\s*load\s+\"(.+)\"\s*$/m.exec(outputData)
-         nsMPM.debug(outputData)
-         if (name) {
-             nsMPM.mpd.set("playlistname", name[1])
-         }
-     }
-     if (priority) {
-         nsMPM.debug("priority command: " + outputData)
-         nsMPM.mpd._cmdQueue.unshift({
-             outputData : outputData + "\n",
-             callBack : nsMPM.Nz(callBack),
-             hide : hide,
-             sent : false
-         })
-     } else {
-         nsMPM.mpd._cmdQueue.push({
-             outputData : outputData + "\n",
-             callBack : nsMPM.Nz(callBack),
-             hide : hide,
-             sent : false
-         })
-     }
-     if (nsMPM.mpd._socket) {
-         nsMPM.mpd._doStatus = true
-         if (nsMPM.mpd._idle) {
-             nsMPM.mpd._socket.writeOut(nsMPM.mpd._cmdQueue[0].outputData)
-             if (!hide)
-                 nsMPM.mpd.set('last_command', outputData);
-             nsMPM.mpd._idle = false
-         }
-     } else {
-         nsMPM.mpd.connect()
-     }
- }
- 
- mpd.getAllDirs = function(callBack) {    
-     if (!nsMPM.mpd._socket)
-         nsMPM.mpd.connect()
-     var cb = callBack
-     nsMPM.mpd.doCmd("listall", function(d) {
-         try {
-             d = d.replace(/^file: .*\n/gm, "")
-             d = d.replace(/^directory: /gm, "")
-             d = d.replace(/^\//gm, "")
-             dirs = d.split("\n").sort().slice(1)
-             var hd = []
-             var l = dirs.length
-             if (l < 1) {
-                 nsMPM.debug("EMPTY getAllDirs() CALLBACK!");
-                 return []
-             }
-             var n = l
-             do {
-                 var name = dirs[l - n]
-                 var path = name.split("/")
-                 var obj = {
-                     Title : path.pop(),
-                     level : path.length,
-                     parent : path.join("/"),
-                     name : name,
-                     type : 'directory',
-                     children : 0
-                 }
-                 if (obj.level > 0) {
-                     for (var pi = hd.length - 1; pi > -1; pi--) {
-                         if (hd[pi].name == obj.parent) {
-                             hd[pi].children += 1
-                             break
-                         }
-                     }
-                 }
-                 hd.push(obj)
-             } while (--n)
-             cb(hd)
-         } catch (e) {
-             nsMPM.debug(e)
-         }
-         return 'undefined';
-     })
- }
- 
- mpd.getArt = function(item, img) {
- 	var fallback = function (code, item, url) {
- 		try{
- 			if ( code == 200 || code == 0 ) {
- 				nsMPM.mpd.cachedArt[url] = url;
- 				img.setAttribute("tooltiptext",url);
- 				img.src = url;
- 				return;
- 			}
- 			if (nsMPM.prefs.get("use_amazon_art", 1) >= 1 ) {
- 				nsMPM.getAmazonArt(nsMPM.mpd, item, img);
- 			} else {
- 				img.src = "chrome://minion/content/images/album_blank.png";
- 				img.removeAttribute("tooltiptext");
- 			}
- 		} catch(e){ nsMPM.debug(e); }
- 	};
- 
- 	try {
- 		if ( typeof(item.file) != 'string' ) {
- 			var art =  "chrome://minion/content/images/album_blank.png";
- 			img.src = art;
- 			img.setAttribute("tooltiptext",art);
- 			return;
- 		}
- 
- 		var strFile = new String(item.file);
- 		if ( strFile.indexOf('http://') == 0 || strFile.indexOf('https://') == 0 ) {
- 			var art =  "chrome://minion/content/images/internet_music.png";
- 			img.src = art;
- 			img.setAttribute("tooltiptext",art);
- 			return;
- 		}
- 		
- 		img.src = "chrome://minion/content/images/album_loading.png";
- 		img.setAttribute("tooltiptext","...");
- 		
- 		if (nsMPM.prefs.get("use_custom_art", false)) {
- 			var url = nsMPM.urlReplace(nsMPM.prefs.get("custom_art_url"), item)
- 			nsMPM.debug("Attempting to fetch cover at " + url);
- 			if (typeof(nsMPM.mpd.cachedArt[url]) != 'string') nsMPM.prefetchImageFromURL(url, fallback, item);
- 			else {
- 				img.setAttribute("tooltiptext",url);
- 				img.src = url;
- 			}
- 		} else {
- 			fallback(404, item);
- 		}
- 	} catch(e) { nsMPM.debug(e); }
- }
- 
- mpd.guessPlaylistName = function () {
-     var playlists = []
-     var aCurPL = []
-     var plinfo = nsMPM.mpd.plinfo
-     
-     for (x=0, l=plinfo.length; x<l; x++) {
-         aCurPL.push(plinfo[x].file)
-     }
-     var currentPL = "file: " + aCurPL.join("\nfile: ") + "\n"
-     
-     var nextPL = function () {
-         pl = playlists.shift().replace(/"/g, '\\"')
-         nsMPM.mpd.doCmd('listplaylist "'+pl+'"', function(data){
-             if (data==currentPL) {
-                 nsMPM.mpd.set("playlistname", pl)
-             } else {
-                 if (playlists.length > 0) nextPL()
-             }
-         }, false)
-     }
-     
-     var q = new nsMPM.dbQuery()
-     q.type = "playlist"
-     q.query = ""
-     q.execute(function(db){
-         for (i in db) playlists.push(db[i].Title)
-         if (playlists.length > 0) nextPL()
-     })
- }
-     
- mpd.searchLyrics = function (q, origCallBack) {
-     q = q.replace(/[^A-Za-z0-9]/g, '%')
-     var url = "http://lyricsfly.com/api/txt-api.php?i={id}&i=" + q
-     url = url.replace("{id}", "14f6b319c854ca8a8-temporary.API.access")
-     //url = url.replace("{id}", nsMPM.prefs.get("lyricsfly_id",""))
-     //url = url.replace("{amo}", "addons.mozilla.org/en-US/firefox/addon/6324")
-     
-     var cb = function(data) {
-         try {
-             var ar = data.getElementsByTagName("ar")
-             var tt = data.getElementsByTagName("tt")
-             nsMPM.debug(tt)
-             var artists = []
-             var titles = []
-             var cmd = null
-             if (tt) {
-                 cmd = "command_list_begin\n"
-                 for (i=0;i<tt.length;i++) {
-                     titles.push(tt[i].textContent)
-                     artists.push(ar[i].textContent)
-                     cmd += 'find title "'+titles[i]+'"\n'
-                 }
-                 cmd += "command_list_end\n"
-             }
-         }
-         catch (e) {nsMPM.debug(e)}
-         if (cmd) {
-             nsMPM.debug(cmd)
-             var db_cb = function (d) {
-                 var db = nsMPM.mpd._parseDB(d)
-                 nsMPM.debug(d)
-                 for (i=0;i<db.length;i++) {
-                     var x = titles.indexOf(db[i].Title)
-                     if (x > -1 && db[i].Artist != artists[x]) {
-                         db.splice(i,1)
-                     }
-                 }
-                 origCallBack(db)
-             }
-             nsMPM.mpd.doCmd(cmd, db_cb)
-         }
-     }
-     nsMPM.debug(url)
-     nsMPM.fetch(url, cb, null, true)
- }
- 
- mpd.getLyrics = function (item, txtLyrics, btnEdit) {
-     if (!nsMPM.Nz(item.Artist)) {
-         txtLyrics.value = nsMPM.translateService.GetStringFromName("no_lyrics_found");
-         btnEdit.edit_link = "http://lyricsfly.com/submit/"
-         return
-     }
-     var cb = function(data) {
-         var lyrics = nsMPM.translateService.GetStringFromName("no_lyrics");
-         try {
-             var tx = data.getElementsByTagName("tx")
-             if (nsMPM.Nz(tx[0])) {
-                 var lyrics = tx[0].textContent.replace(/\[br\]/g,"")
-                 var cs = data.getElementsByTagName("cs")
-                 var id = data.getElementsByTagName("id")
-                 if (nsMPM.Nz(cs[0]) && nsMPM.Nz(id[0]) && nsMPM.Nz(btnEdit)) {
-                     var ed = "http://lyricsfly.com/search/correction.php?[CHECKSUM]&id=[SONG ID]"
-                     ed = ed.replace("[CHECKSUM]", cs[0].textContent)
-                     ed = ed.replace("[SONG ID]", id[0].textContent)
-                     btnEdit.edit_link = ed
-                 }
-             }
-         }
-         catch (e) {nsMPM.debug(e)}
-         finally { txtLyrics.value = lyrics }
-     }
-     var url = "http://lyricsfly.com/api/api.php?i={id}-{amo}&a={Artist}&t={Title}"
-     // Please do not attempt to use this user id for api access.
-     // It is easy to obtain your own id, please see http://lyricsfly.com/api/
-     url = url.replace("{id}", nsMPM.prefs.get("lyricsfly_id",""))
-     url = url.replace("{amo}", "addons.mozilla.org/en-US/firefox/addon/6324")
-     url = url.replace("{Artist}", nsMPM.Nz(item.Artist, '').replace(/[^A-Za-z0-9]/g, '%'))
-     url = url.replace("{Title}", nsMPM.Nz(item.Title, '').replace(/[^A-Za-z0-9]/g, '%'))
-     txtLyrics.value = nsMPM.translateService.GetStringFromName("searching_lyrics");
-     btnEdit.edit_link = "http://lyricsfly.com/submit/"
-     nsMPM.fetch(url, cb, null, true)
- }
- 
- mpd.getOutputs = function(callBack) {
-     var cb = function(data) {
-         // Parse the incoming data into an array of output objects
-         var obj = []
-         data = data.split("\n")
-         var dl = data.length - 2
-         for (var i = 0; i < dl; i++) {
-             var sep = data[i].indexOf(": ")
-             if (sep > 0) {
-                 var idx = data[i].slice(sep + 2)
-                 var name = "unknown"
-                 var enabled = false
-                 sep = data[++i].indexOf(": ")
-                 if (sep > 0) {
-                     name = data[i].slice(sep + 2)
-                     sep = data[++i].indexOf(": ")
-                     if (sep > 0) {
-                         enabled = (data[i].slice(sep + 2) == 1) ? true : false
-                     }
-                 }
-                 obj[idx] = {
-                     id : idx,
-                     name : name,
-                     enabled : enabled
-                 }
-             }
-         }
-         callBack(obj)
-     }
-     nsMPM.mpd.doCmd('outputs', cb)
- }
- 
- mpd.setServers = function(servers) {
- 	nsMPM.mpd.set('servers', servers);
- 	try {
- 		var file = nsMPM.DirIO.get(nsMPM.pref_dir);
- 		file.append(nsMPM.pref_file_servers);
- 		if (!file.exists()) {
- 			nsMPM.FileIO.create(file);
- 		}
- 		var str = nsMPM.JSON.stringify(nsMPM.mpd.servers);
- 		nsMPM.FileIO.write(file, str);
- 		file = null;
- 	} catch(e) { nsMPM.debug(e); }
- }
- 
- mpd.loadServers = function() {
- 	var file = nsMPM.DirIO.get(nsMPM.pref_dir);
- 	file.append(nsMPM.pref_file_servers);
- 	if (file.exists()) {
- 		nsMPM.debug("Reading server nsMPM.prefs from: "+file.path);
- 		var str = nsMPM.FileIO.read(file);
- 		nsMPM.mpd.servers = nsMPM.JSON.parse(str);
- 	} else {
- 		// creating default server
- 		var s,p;
- 		if ( nsMPM.env.exists('MPD_HOST') ) {
- 			s = nsMPM.env.get('MPD_HOST');
- 			if ( nsMPM.env.exists('MPD_PORT')) {
- 				p = nsMPM.env.get('MPD_PORT');
- 			} else {
- 				p = 6600; // this is the default mpd port
- 			}
- 			nsMPM.debug('Found MPD environment settings');
- 			nsMPM.mpd.servers = [[s, s+':'+p+':']]
- 			nsMPM.mpd.setServers(nsMPM.mpd.servers);
- 			nsMPM.prefs.set("server",nsMPM.mpd.servers[0][1]);
- 		} else {
- 			nsMPM.debug("Creating default servers.");
- 			nsMPM.mpd.servers = default_servers;
- 			nsMPM.mpd.setServers(nsMPM.mpd.servers);
- 			nsMPM.prefs.set("server",nsMPM.mpd.servers[0][1]);
- 		}
- 	}
- 	file = null;
- }
- 
- // Any property that may be observed must be set with this method.
- mpd.set = function(prop, val) {
-     if (val != nsMPM.mpd[prop]) {
-         //nsMPM.debug("Notify: nsMPM.mpd."+prop+" = "+val)
-         nsMPM.mpd[prop] = val
-         nsMPM.observerService.notifyObservers(null, prop, val)
-     }
- }
- 
- mpd.toggleRandom = function() {
-     var state = (nsMPM.mpd.random > 0) ? 0 : 1
-     nsMPM.mpd.doCmd("random " + state)
- }
- 
- mpd.toggleRepeat = function() {
-     var state = (nsMPM.mpd.repeat > 0) ? 0 : 1
-     nsMPM.mpd.doCmd("repeat " + state)
- }
- 
- mpd.load_pls_stream = function(data, action) {
- 	try {
- 		var itemCount=0;
- 		if (typeof(action) == 'undefined') action = "add";
- 		var urls = data.match(/(?:File\d+=)(.+)(?:[\n|\r])/ig)
- 		var cmd = 'command_list_begin'
- 		if (action == "replace") cmd += "\nclear";
- 		for (x in urls) {
- 			var u = urls[x].replace("\n", "").replace(/File\d+=/gi, "")
- 			if (u.length > 0) {
- 				cmd += '\nadd ' + u;
- 				itemCount++;
- 			}
- 		}
- 		cmd += '\ncommand_list_end'
- 		nsMPM.mpd.doCmd(cmd)
- 	} catch(e){ nsMPM.debug(e); }
- 	return itemCount;
- }
- 
- mpd.load_m3u_stream = function(data, action) {
- 	try {
- 		var itemCount=0;
- 		if (typeof(action) == 'undefined') action = "add"
- 		urls = data.replace(/^#.+$/mg, "").replace(/\r/mg,'').split("\n")
- 		var cmd = 'command_list_begin';
- 		if (action == "replace") cmd += "\nclear";
- 		for (x in urls) {
- 			var u = urls[x];
- 			if (u.length > 0) {
- 				cmd += '\nadd ' + u;
- 				itemCount++;
- 			}
- 		}
- 		cmd += '\ncommand_list_end';
- 		nsMPM.mpd.doCmd(cmd);
- 	} catch(e){ nsMPM.debug(e); }
- 	return itemCount;
- }
- 
- mpd.load_xspf_stream = function(data, action) {
- 	try {
- 		var itemCount=0;
- 		if (typeof(action) == 'undefined') action = "add";
- 		urls = data.getElementsByTagName("location");
- 		var cmd = 'command_list_begin';
- 		if (action == "replace") cmd += "\nclear";
- 		for (var x=0; x < urls.length; x++) {
- 			var u = urls.item(x);
- 			if ( u.textContent.length > 0 ) {
- 				cmd += '\nadd ' + u.textContent;
- 				itemCount++;
- 			}
- 		}
- 		cmd += '\ncommand_list_end';
- 		nsMPM.mpd.doCmd(cmd);
- 	} catch(e){ nsMPM.debug(e); }
- 	return itemCount;
- }
- 
- mpd.prefObserver = {
- 	obs: null,
- 	register : function() {
- 		this.obs = nsMPM.prefs.getObserver("server",nsMPM.mpd.loadSrvPref);
- 	},
- 	unregister : function() {
- 		this.obs.unregister();
- 	}
- }
- 
- mpd.loadSrvPref = function() {
- 	var srv = ''
- 	if (nsMPM.prefs.isPref("server") == true) {
- 		var srv = nsMPM.prefs.get("server",default_servers[0]);
- 	}
- 	nsMPM.debug('srv = '+srv)
- 	if (srv > '') {
- 		srv = srv.split(":", 3);
- 		var cb = function() {
- 			nsMPM.mpd._cmdQueue = [];
- 			if (srv.length == 3) {
- 				nsMPM.mpd._host = srv[0];
- 				nsMPM.mpd._port = parseInt(srv[1]);
- 				nsMPM.mpd._password = srv[2];
- 				nsMPM.mpd.connect();
- 				nsMPM.observerService.notifyObservers(null, "new_mpd_server", srv[0] + ":" + srv[1]);
- 			} else {
- 				nsMPM.mpd._host = null;
- 				nsMPM.mpd._port = null;
- 				nsMPM.observerService.notifyObservers(null, "new_mpd_server", null);
- 			}
- 		}
- 		var timer = Components.classes["@mozilla.org/timer;1"]
- 					.createInstance(Components.interfaces.nsITimer);
- 		nsMPM.mpd.disconnect();
- 		timer.initWithCallback(cb, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
- 	} else {
- 		nsMPM.debug("No server, disconnecting.");
- 		nsMPM.mpd.disconnect();
- 	}
- }
- 
- function socketTalker() {
-     if (nsMPM.mpd._port <= '' || nsMPM.mpd._host <= '') return null
-     nsMPM.debug("enter socketTalker")
-     nsMPM.mpd.set('greeting', 'Connecting...');
-     var initialized = false
-     var regGreet = /OK MPD [0-9\.]+\n/gm
-     try {
-         var transportService = Components.classes["@mozilla.org/network/socket-transport-service;1"]
-                 .getService(Components.interfaces.nsISocketTransportService);
-         var transport = transportService.createTransport(null, 0, nsMPM.mpd._host,
-                 nsMPM.mpd._port, null);
-         var outstream = transport.openOutputStream(0, 0, 0);
-         var instream = transport.openInputStream(0, 0, 0);
-         const replacementChar = Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
-         var utf_instream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
-                 .createInstance(Components.interfaces.nsIConverterInputStream);
-         var utf_outstream = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
-                 .createInstance(Components.interfaces.nsIConverterOutputStream)
- 
-         utf_instream.init(instream, 'UTF-8', 1024, replacementChar);
-         utf_outstream.init(outstream, 'UTF-8', 0, 0x0000)
-     } catch (e) {
-         nsMPM.mpd._host = null
-         nsMPM.mpd._port = null
-         nsMPM.mpd._password = null
-         nsMPM.mpd.disconnect()
-         return null
-     }
- 
-     var listener = {
-         data : "",
-         onStartRequest : function(request, context) {
-             nsMPM.mpd._idle = false
-             nsMPM.mpd.cachedDB = []
-             initialized = false
-             nsMPM.debug('socketTalker for server ' + nsMPM.mpd._host + ":" + nsMPM.mpd._port
-                     + " created.")
-             nsMPM.mpd.set('greeting', nsMPM.translateService.GetStringFromName('connecting'));
-         },
-         onStopRequest : function(request, context, status) {
-             this.data = null
-             nsMPM.debug('socketTalker for server ' + nsMPM.mpd._host + ":" + nsMPM.mpd._port
-                     + " destroyed.")
-             nsMPM.debug('close status = ' + status)
-             nsMPM.mpd._socket = null
-             nsMPM.mpd.set('greeting', nsMPM.translateService.GetStringFromName('not_connected'));
-             if (status == NOSRV_STATUS) {
-                 nsMPM.mpd._host = null
-                 nsMPM.mpd._port = null
-                 nsMPM.mpd._password = null
-                 nsMPM.debug("Killing socket")
-             }
-         },
-         onDataAvailable : function(request, context, inputStream, offset, count) {
-             try {
-                 nsMPM.mpd._idle = false
-                 var str = {};
-                 var chunks = []
-                 var chlen = 0
-                 var done = false
-                 while (utf_instream.readString(4096, str) != 0) {
-                     chunks[chlen++] = str.value
-                 }
-                 this.data += chunks.join("")
-                 str = null
-                 if (!initialized) {
-                     var greet = this.data.match(regGreet)
-                     if (greet) {
-                         initialized = true
-                         this.data = this.data.replace(regGreet, "")
-                         nsMPM.mpd.set('greeting', "MPD@" + nsMPM.mpd._host
-                                 + ":" + nsMPM.mpd._port)
-                         if (nsMPM.mpd._password.length > 0) {
-                             nsMPM.mpd._cmdQueue.unshift({
-                                 outputData : 'password "' + nsMPM.mpd._password
-                                         + '"\n',
-                                 callBack : null,
-                                 hide : true
-                             })
-                         }
-                         if (nsMPM.mpd._cmdQueue.length > 0) {
-                             var snd = nsMPM.mpd._cmdQueue[0].outputData
-                             utf_outstream.writeString(snd);
-                             if (!nsMPM.mpd._cmdQueue[0].hide) {
-                                 nsMPM.mpd.set('last_command', snd);
-                                 nsMPM.mpd.set('lastResponse', nsMPM.translateService.GetStringFromName("working"));
-                             } else if (snd.slice(0, 9) == "plchanges") {
-                                 nsMPM.mpd.set('lastResponse', nsMPM.translateService.GetStringFromName("working"));
-                             }
-                         } else {
-                             done = true
-                         }
-                         nsMPM.observerService.notifyObservers(null, "new_connection",
-                                 null)
-                     }
-                 }
-                 if (this.data.substr(-3) == "OK\n") {
-                     var cdata = this.data.split(/^OK\n/gm)
-                     this.data = ""
-                     while (cdata.length > 1) {
-                         var d = cdata.shift()
-                         if (nsMPM.mpd._cmdQueue.length > 0) {
-                             var snd = nsMPM.mpd._cmdQueue[0].outputData
-                             if (!nsMPM.mpd._cmdQueue[0].hide) {
-                                 nsMPM.mpd.set('lastResponse', "OK");
-                             } else if (snd.slice(0, 9) == "plchanges") {
-                                 nsMPM.mpd.set('lastResponse', "OK");
-                             }
-                             if (nsMPM.mpd._cmdQueue[0].callBack) {
-                                 nsMPM.mpd._cmdQueue[0].callBack(d)
-                             }
-                             nsMPM.mpd._cmdQueue.shift()
-                         }
-                     }
-                     if (nsMPM.mpd._cmdQueue.length > 0) {
-                         var snd = nsMPM.mpd._cmdQueue[0].outputData
-                         utf_outstream.writeString(snd);
-                         if (!nsMPM.mpd._cmdQueue[0].hide) {
-                             nsMPM.mpd.set('last_command', snd);
-                             nsMPM.mpd.set('lastResponse', nsMPM.translateService.GetStringFromName("working"));
-                         } else if (snd.slice(0, 9) == "plchanges") {
-                             nsMPM.mpd.set('lastResponse', nsMPM.translateService.GetStringFromName("working"));
-                         }
-                     } else {
-                         done = true
-                     }
-                 } else if (this.data.indexOf('ACK [') != -1) {
-                     nsMPM.mpd.set('lastResponse', this.data.replace(/\n/g, ""))
-                     nsMPM.mpd._cmdQueue.shift()
-                     done = true
-                 }
- 
-                 if (done) {
-                     if (nsMPM.mpd._doStatus) {
-                         nsMPM.mpd._doStatus = false
-                         nsMPM.mpd._cmdQueue.push({
-                             outputData : "command_list_begin\nstatus\nstats\ncommand_list_end\n",
-                             callBack : nsMPM.mpd._update,
-                             hide : true,
-                             sent : true
-                         })
-                         utf_outstream.writeString("command_list_begin\nstatus\nstats\ncommand_list_end\n")
-                     } else {
-                         nsMPM.mpd._idle = true
-                     }
-                 }
-             } catch (e) {
-                 nsMPM.mpd._host = null
-                 nsMPM.mpd._port = null
-                 nsMPM.mpd.disconnect()
-                 nsMPM.debug(e)
-             }
-         }
-     }
- 
-     var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"]
-             .createInstance(Components.interfaces.nsIInputStreamPump);
-     pump.init(instream, -1, -1, 0, 0, false);
-     pump.asyncRead(listener, null);
- 
-     var con = {
-         cancel : function() {
-             nsMPM.debug("Cancel socket")
-             transport.close(0)
-         },
-         writeOut : function(str) {
-             if (initialized)
-                 utf_outstream.writeString(str)
-         }
-     }
- 
-     return con
- } // end socketTalker()
- 
- 
- function dbQuery(cmd, callBack) {
-     this.cmd = nsMPM.Nz(cmd);
-     this.path = [];
-     this.type = 'directory';
-     this.scope = null;
-     this.query = null;
-     this.restrict = null;
-     this.filterField = null;
-     this.filterQuery = null;
-     this.callBack = nsMPM.Nz(callBack);
-     this.dbMatches = null;
- }
- 
- dbQuery.prototype.evaluate = function() {
-     if (this.cmd) {
-         var cmd = this.cmd
-         // Clean up and validate nsMPM.mpd.doCmd lists.
-         if (cmd.indexOf('command_list_begin') > -1) {
-             if (cmd.indexOf('command_list_end') < 0) {
-                 cmd += "\ncommand_list_end"
-             }
-         } else if (cmd.indexOf(';') > -1) {
-             cmd = "command_list_begin;" + cmd
-             if (cmd.indexOf('command_list_end') < 0) {
-                 cmd += ";command_list_end"
-             }
-             cmd = cmd.replace(/;/g, "\n")
-         }
- 
-         // Check if this nsMPM.mpd.doCmd returns database results.
-         // If so, check if it will return multiple sets that
-         // will need to be combined.
-         var re = /^.*search |^.*find |^.*info|^plchanges |^list.* /gm
-         this.dbMatches = cmd.match(re)
-         this.cmd = cmd
-         return cmd
-     }
- 
-     switch (this.type) {
-         case 'search' :
-             this.cmd = "search";
-             this.path = [{
-                 type : "search",
-                 Title : "Search (" + this.scope + "): " + this.query,
-                 name : this.query
-             }];
-             break;
-         case 'playlistsearch' :
-             this.cmd = "playlistsearch";
-             this.path = [{
-                 type : "playlistsearch",
-                 Title : "Search Playlist (" + this.scope + "): " + this.query,
-                 name : this.query
-             }];
-             break;
-         case 'directory' :
-             this.cmd = "lsinfo";
-             this.path = [{
-                 type : 'directory',
-                 Title : "Folders",
-                 name : ""
-             }];
-             if (nsMPM.Nz(this.query, "") == "") {
-                 this.restrict = ["directory", "file"];
-             }
-             var p = this.query.split("/");
-             if (p.length > 0) {
-                 for (var i = 0; i < p.length; i++) {
-                     if (p[i] > "") {
-                         this.path.push({
-                                     type : 'directory',
-                                     Title : p[i],
-                                     name : p.slice(0, i + 1).join("/")
-                                 })
-                     }
-                 }
-             }
-             break;
-         case 'file' :
-             this.cmd = "find";
-             this.path = [{
-                 type : this.scope,
-                 Title : this.scope + "s",
-                 name : ""
-             }, {
-                 type : this.scope,
-                 Title : this.query,
-                 name : this.query
-             }];
-             break;
-         case 'playlist' :
-             this.path = [{
-                 type : "playlist",
-                 Title : "Playlists",
-                 name : ""
-             }];
-             if (nsMPM.Nz(this.query, "") == "") {
-                 this.cmd = "lsinfo";
-                 this.restrict = "playlist";
-             } else {
-                 this.cmd = "listplaylistinfo";
-                 this.path.push({
-                             type : "playlist",
-                             Title : this.query,
-                             name : this.query
-                         });
-             }
-             ;
-             break;
-         case 'current_playlist' :
-             this.path = [{
-                 type : "playlist",
-                 Title : "Playlists",
-                 name : ""
-             }];
-             break;
-         default :
-             this.cmd = "list " + this.type;
-             this.path = [{
-                 type : this.type,
-                 Title : this.type + "s",
-                 name : ""
-             }];
-             break;
-     }
-     if (this.scope)
-         this.cmd += " " + this.scope;
-     if (this.query)
-         this.cmd += " " + nsMPM.Sz(this.query);
-     this.dbMatches = 1
-     return 'undefined';
- }
- 
- dbQuery.prototype.execute = function(callBack) {
-     if (!nsMPM.mpd._socket) {
-         nsMPM.mpd.connect()
-         nsMPM.debug("dbQuery forcing connect.")
-     }
-     callBack = nsMPM.Nz(callBack, this.callBack)
-     this.evaluate()
-     var cmd = this.cmd
-     var path = this.path
-     var restrict = this.restrict
-     var useCache = !(this.type == 'playlist' || this.restrict)
- 
-     if (nsMPM.Nz(nsMPM.mpd.cachedDB[cmd])) {
-         nsMPM.debug("cached: " + cmd)
-         callBack(nsMPM.mpd.cachedDB[cmd])
-         return null
-     }
- 
-     if (!this.dbMatches) {
-         nsMPM.mpd.doCmd(cmd, null, false)
-         return null
-     } else {
-         var chkDupes = (this.dbMatches.length > 1)
-     }
- 
-     if (this.filterField) useCache = false
-     var filterField = this.filterField
-     var filterQuery = this.filterQuery
-     var isPlaylists = (this.type=='playlist' && this.query=='')
-     nsMPM.mpd.doCmd(cmd, function(d) {
-         var db = nsMPM.mpd._parseDB(d)
-         if (restrict)
-             db = dbFilter(db, restrict)
-         if (chkDupes)
-             db = dbDistinct(db)
-         if (nsMPM.prefs.get("linguistic_sort", true) || isPlaylists) db.sort(nsMPM.smartsort)
-         if (useCache && db.length > 0)
-             nsMPM.mpd.cachedDB[cmd] = db
-         if (filterField) {
-             db = [x for each  (x in db) if (x[filterField]==filterQuery)]
-         }
-         callBack(db, path)
-     }, false)
-     return true
- }
- 
- 
- function dbDistinct(db) {
-     var rdb = []
-     var dl = db.length
-     if (dl < 1) {
-         return db
-     }
-     var n = dl
- 
-     var srt = function(a, b) {
-         if (a.name < b.name)
-             return -1
-         if (a.name > b.name)
-             return 1
-         return 0
-     }
- 
-     db.sort(srt)
-     do {
-         var i = dl - n
-         if (n == 1) {
-             rdb.push(db[i])
-         } else if (db[i].name != db[i + 1].name) {
-             rdb.push(db[i])
-         }
-     } while (--n)
-     return rdb
- }
- 
- function dbFilter(db, restrict) {
-     var rdb = []
-     var dl = db.length
-     if (dl < 1) {
-         return db
-     }
-     if (typeof(restrict) == 'string')
-         restrict = [restrict]
-     for (var i = 0; i < restrict.length; i++) {
-         var n = dl
-         var r = restrict[i]
-         do {
-             if (db[dl - n].type == r) {
-                 rdb.push(db[dl - n])
-             }
-         } while (--n)
-     }
-     return rdb
- }
- 
--- 0 ----
diff -c -r -N minion.orig//chrome/resource/mpmCommon.js minion.patched//chrome/resource/mpmCommon.js
*** minion.orig//chrome/resource/mpmCommon.js	2012-03-30 23:07:40.145062918 +0200
--- minion.patched//chrome/resource/mpmCommon.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,28 ****
- var EXPORTED_SYMBOLS = [ "nsMPM" ];
- 
- /**
-  * nsMPM namespace.
-  */
- if ("undefined" == typeof(nsMPM) || nsMPM == null ) {
- 	var nsMPM = {
- 		Cc: Components.classes,
- 		Ci: Components.interfaces,
- 		Cu: Components.utils,
- 		JSON: null,
- 		FileIO: null,
- 		DirIO: null,
- 		mpmMenu: null,
- 		mpd: null,
- 		mpmUpgrade: null,
- 		
- 		pref_dir: "ProfD", // http://mxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h
- 		pref_file_servers: "mpm_servers.js",
- 		pref_file_menus: "mpm_menus.js",
- 		
- 		instance_count: 0
- 	};
- }
- 
- // independent js modules
- if (nsMPM.JSON == null) Components.utils.import("resource://minion/JSON.js",nsMPM);
- if (nsMPM.FileIO == null )Components.utils.import("resource://minion/io.js",nsMPM);
--- 0 ----
diff -c -r -N minion.orig//chrome/resource/mpmMenu.js minion.patched//chrome/resource/mpmMenu.js
*** minion.orig//chrome/resource/mpmMenu.js	2012-03-30 23:07:40.145062918 +0200
--- minion.patched//chrome/resource/mpmMenu.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,293 ****
- Components.utils.import("resource://minion/mpmUtils.js");
- 
- let EXPORTED_SYMBOLS = ["mpmMenu"]
- 
- var mpmMenu = {
- 	items: [],
- 	_loadDefaults : function () {
- 		this.items = [
- 			{
- 				id : "mpm_menu_toggle_cs",
- 				label : nsMPM.translateService.GetStringFromName("toggle_song_display"),
- 				locations : "statusbar",
- 				targets : null,
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "nsMPM.prefs.set (\n    'sb_currentsong_hide',\n    !nsMPM.prefs.get('sb_currentsong_hide')\n);"
- 			}, {
- 				id : "mpm_menu_add",
- 				label : nsMPM.translateService.GetStringFromName("add_to_playlist"),
- 				locations : "mpdbrowser",
- 				targets : "file directory Artist Album Date Genre Performer Composer",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "mpdbrowser.addSelected()"
- 			}, {
- 				id : "mpm_menu_replace",
- 				label : nsMPM.translateService.GetStringFromName("replace_playlist"),
- 				locations : "mpdbrowser",
- 				targets : "file directory Artist Album Date Genre Performer Composer",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : "clear",
- 				script : "mpdbrowser.addSelected()"
- 			}, {
- 				id : "mpm_menu_viewDetails",
- 				label : nsMPM.translateService.GetStringFromName("view_song_details"),
- 				locations : null,
- 				targets : "file",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "mpdbrowser.showDetails(item)"
- 			}, {
- 				id : "mpm_menu_setFileAction",
- 				label : nsMPM.translateService.GetStringFromName("set_default_action"),
- 				locations : "mpdbrowser",
- 				targets : "file",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "nsMPM.mpm_openDialog('chrome://minion/content/fileActions.xul', 'mpm_file_actions')"
- 			}, {
- 				id : "mpm_menu_update",
- 				label : nsMPM.translateService.GetStringFromName("update_this_folder"),
- 				locations : null,
- 				targets : "directory",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "mpdbrowser.doUpdate()"
- 			}, "separator", {
- 				id : "mpm_menu_loadPlaylist",
- 				label : nsMPM.translateService.GetStringFromName("load_playlist"),
- 				locations : "mpdbrowser",
- 				targets : "playlist",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : "clear; load {Title}",
- 				script : null
- 			}, {
- 				id : "mpm_custom_playlistAppend",
- 				label : nsMPM.translateService.GetStringFromName("append_playlist"),
- 				locations : "mpdbrowser",
- 				targets : "playlist",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : "load {Title}",
- 				script : null
- 			}, {
- 				id : "mpm_menu_rmPlaylist",
- 				label : nsMPM.translateService.GetStringFromName("delete_playlist"),
- 				locations : "mpdbrowser",
- 				targets : "playlist",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : "rm {Title}",
- 				script : null
- 			}, {
- 				id : "mpm_menu_renPlaylist",
- 				label : nsMPM.translateService.GetStringFromName("rename_playlist"),
- 				locations : "mpdbrowser",
- 				targets : "playlist",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "var name = prompt(\""+nsMPM.translateService.GetStringFromName("enter_new_name")+"\", item.Title);\nif (name) nsMPM.mpd.doCmd(\"rename \"+nsMPM.Sz(item.Title)+\" \"+nsMPM.Sz(name))"
- 			}, "separator", {
- 				id : "mpm_menu_playlistRemove",
- 				label : nsMPM.translateService.GetStringFromName("remove_from_playlist"),
- 				locations : "mpdplaylist",
- 				targets : "file",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "mpdplaylist.delete()"
- 			}, {
- 				id : "mpm_menu_playlistmvFirst",
- 				label : nsMPM.translateService.GetStringFromName("move_to_begining_playlist"),
- 				locations : "mpdplaylist",
- 				targets : "file",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "mpdplaylist.moveFirst()"
- 			}, {
- 				id : "mpm_menu_playlistmvNext",
- 				label : nsMPM.translateService.GetStringFromName("move_to_next_in_queue"),
- 				locations : "mpdplaylist",
- 				targets : "file",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "mpdplaylist.moveNext()"
- 			}, {
- 				id : "mpm_menu_playlistmvLast",
- 				label : nsMPM.translateService.GetStringFromName("move_to_end_playlist"),
- 				locations : "mpdplaylist",
- 				targets : "file",
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "mpdplaylist.moveLast()"
- 			}, {
- 				id : "mpm_menu_ClearPlaylist",
- 				label : nsMPM.translateService.GetStringFromName("clear_playlist"),
- 				locations : "mpdplaylist",
- 				targets : null,
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : "clear",
- 				script : null
- 			}, {
- 				id : "mpm_menu_SavePlaylist",
- 				label : nsMPM.translateService.GetStringFromName("save_playlist_as"),
- 				locations : "mpdplaylist",
- 				targets : null,
- 				URL : null,
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : "var name = prompt('"+nsMPM.translateService.GetStringFromName("enter_playlist_name")+"');\n"+
- 					"nsMPM.mpd.doCmd('save \"' + name.replace(/\"/g, '\\\"') + '\"')"
- 			}, "separator", {
- 				id : "mpm_menu_google",
- 				label : nsMPM.translateService.GetStringFromName("google_it"),
- 				locations : null,
- 				targets : "file Artist Album",
- 				URL : "http://www.google.com/search?q={Artist}+{Title}",
- 				queryType : null,
- 				queryScope : null,
- 				filterField: null,
- 				mpdCommand : null,
- 				script : null
- 			}, {
- 				id : "mpm_menu_viewAlbum",
- 				label : nsMPM.translateService.GetStringFromName("view_this_album"),
- 				locations : null,
- 				targets : "file",
- 				URL : null,
- 				queryType : "file",
- 				queryScope : "Album",
- 				filterField: null,
- 				mpdCommand : null,
- 				script : null
- 			}, {
- 				id : "mpm_menu_viewArtistAlbum",
- 				label : nsMPM.translateService.GetStringFromName("view_albums_by_artist"),
- 				locations : null,
- 				targets : "file Artist",
- 				URL : null,
- 				queryType : "Album",
- 				queryScope : "Artist",
- 				filterField: null,
- 				mpdCommand : null,
- 				script : null
- 			}
- 		]
- 	},
- 	/* "locations" and "targets":
- 	 * Determines when menuitem is shown.  
- 	 * "locations" matches tag names:
- 	 *      mpdbrowser, mpdplaylist, currentsong, etc.
- 	 * "targets" matches type of item clicked on:
- 	 *      file, Artist, Album, playlist, etc.
- 	 * Null values matches any.
- 	 * 
- 	 * "URL", "query*", "mpdCommand":
- 	 * Place item and mpd values in {} to have them replaced
- 	 * at runtime.  URL loads web pages, queries lookup in the
- 	 * database and displays results, mpdCommand uses the MPD protocol.
- 	 * Use ; to seperate multiple commands in mpdCommand.
- 	 * i.e.: mpdCommand = "add {file};play {playlistlength}"
- 	 * 
- 	 * "script" will be evaluated at runtime.
- 	 */
- 	mpmMenuItem : function (label, id) {
- 		var newItem = {};
- 		
- 		newItem.id = nsMPM.Nz(id, "mpm_custom_menuItem")
- 		newItem.label = nsMPM.Nz(label, nsMPM.translateService.GetStringFromName("new_menu_item"))
- 		
- 		newItem.locations = null
- 		newItem.targets = null
- 		
- 		newItem.URL = null
- 		newItem.queryType = null
- 		newItem.queryScope = null
- 		newItem.filterField = null
- 		newItem.mpdCommand = null
- 		newItem.script = null
- 		return newItem;
- 	},
- 	_loadMenuItems : function () {
- 		try {
- 			let that = this;
- 			var file = nsMPM.DirIO.get(nsMPM.pref_dir);
- 			file.append(nsMPM.pref_file_menus);
- 			if (file.exists()) {
- 				nsMPM.debug("Read menus from "+file.path);
- 				var str = nsMPM.FileIO.read(file);
- 				that.items = nsMPM.JSON.parse(str);
- 			} else {
- 				nsMPM.debug("Creating default menus.")
- 				this._loadDefaults();
- 				this._saveMenuItems();
- 			}
- 			file = null;
- 		} catch(e){dump(e+"\n"); dump(this+"\n")}
- 	},
- 	_saveMenuItems : function() {
- 		let that = this;
- 		var file = nsMPM.DirIO.get(nsMPM.pref_dir);
- 		file.append(nsMPM.pref_file_menus);
- 		nsMPM.debug("Saving menus to :"+file.path);
- 		if (!file.exists()) {
- 			nsMPM.FileIO.create(file);
- 		}
- 		var str = nsMPM.JSON.stringify(that.items);
- 		nsMPM.FileIO.write(file, str);
- 		file = null;
- 	},
- 	
- 	load: function() { this._loadMenuItems(); },
- 	restore: function () { this._loadDefaults(); this._saveMenuItems() },
- 	save: function() { this._saveMenuItems(); }
- }
- 
- 
- 
- 
--- 0 ----
diff -c -r -N minion.orig//chrome/resource/mpmUpgrade.js minion.patched//chrome/resource/mpmUpgrade.js
*** minion.orig//chrome/resource/mpmUpgrade.js	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/resource/mpmUpgrade.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,251 ****
- Components.utils.import("resource://minion/mpmUtils.js");
- 
- let EXPORTED_SYMBOLS = ["mpmUpgrade"]
- 
- // Old variables. Now discarder. see mpmCommon.js.
- var pref_dir_old = "Home";
- var pref_file_menus_old = ".mpm_menus.js";
- var pref_file_servers_old = ".mpm_servers.js";
- var pref_file_state_old = ".mpm_browser_state.js";
- 
- var mpmUpgrade = {};
- 
- function mpmUpgrade206(mpd) {
- 	try {
- 		if ( nsMPM.prefs.isPref('use_amazon_art') ) {
- 			if (typeof(nsMPM.prefs.get("use_amazon_art",1)) == "boolean" ) nsMPM.prefs.clear("use_amazon_art");
- 		}
- 
- 		// it is not possible to restore old menus stored in JS and get them converted to JSON
- 		// So, we have to restore defaults value.
- 		// This concerns only "beta" user of 2.0.x branch
- 		var file = nsMPM.DirIO.get(pref_dir_old);
- 		file.append(pref_file_menus_old);
- 		if (file.exists()) {
- 			nsMPM.FileIO.unlink(file);
- 		}
- 		nsMPM.mpmMenu.restore(); // Will overwrite any already migrated menus
- 
- 		nsMPM.debug('Upgrade for 2.0.6: Ok');
- 	} catch(e) {
- 		nsMPM.debug('Upgrade for 2.0.6: Failed');
- 		nsMPM.debug(e);
- 	}
- 	return true;
- }
- 
- function mpmUpgrade204(mpd) {
- 	try {
- 		if ( nsMPM.prefs.isPref('persistant_state') ) nsMPM.prefs.clear("persistant_state");
- 
- 		var file = nsMPM.DirIO.get(pref_dir_old);
- 		file.append(pref_file_state_old);
- 		if (file.exists()) nsMPM.FileIO.unlink(file);
- 
- 		nsMPM.debug('Upgrade for 2.0.4: Ok');
- 	} catch(e) {
- 		nsMPM.debug('Upgrade for 2.0.4: Failed');
- 		nsMPM.debug(e);
- 	}
- 	return true;
- }
- 
- function mpmUpgrade200(mpd) {
- 	try {
- 		var file = nsMPM.DirIO.get(pref_dir_old);
- 		file.append(pref_file_servers_old);
- 		if (file.exists()) {
- 			nsMPM.debug('Upgrading old server nsMPM.prefs');
- 			var str = nsMPM.FileIO.read(file);
- 			nsMPM.mpd.servers = nsMPM.JSON.parse(str);
- 			nsMPM.FileIO.unlink(file);
- 			nsMPM.mpd.setServers(nsMPM.mpd.servers);
- 		}
- 		nsMPM.debug('Upgrade for 2.0.0: Ok');
- 	} catch(e) {
- 		nsMPM.debug('Upgrade for 2.0.0: Failed');
- 		nsMPM.debug(e);
- 	}
- 	return true;
- }
- 
- function mpmUpgrade144(mpd) {
- 	try {
- 		var host = nsMPM.prefs.get('mpd_host');
- 		var port = nsMPM.prefs.get('mpd_port');
- 		var password = nsMPM.prefs.get('mpd_password');
- 
- 		nsMPM.prefs.set('server',host+':'+port+':'+password);
- 
- 		var servers = [];
- 		var server = [];
- 		server.push('MPD server');
- 		server.push(host+':'+port+':'+password);
- 		servers.push(server);
- 		
- 		nsMPM.mpd.setServers(servers);
- 
- 		nsMPM.prefs.clear("mpd_host");
- 		nsMPM.prefs.clear("mpd_port");
- 		nsMPM.prefs.clear("mpd_password");
- 		nsMPM.prefs.clear("playlist_mode");
- 		nsMPM.prefs.clear("home");
- 
- 		nsMPM.debug('Upgrade for 1.4.4: Ok');		
- 	} catch(e) {
- 		nsMPM.debug('Upgrade for 1.4.4: Failed');
- 		nsMPM.debug(e);
- 	}
- 	return true;
- }
- 
- function mpmCleanOldPrefs() {
- 	oldPrefs = ["mpd_host", "mpd_port", "mpd_password", "playlist_mode", "home", "use_amazon_art", "persistant_state"];
- 	for(i=0; i<oldPrefs.length; i++){
- 		if ( nsMPM.prefs.isPref(oldPrefs[i]) ) nsMPM.prefs.clear(oldPrefs[i]);
- 	}
- }
- 
- function mpmGetPreviousVersion() {
- 	if ( nsMPM.prefs.isPref('version') ) return nsMPM.prefs.get('version');
- 
- 	if ( nsMPM.prefs.isPref('save_art_url') ) return '2.0.8';
- 	
- 	var menus_file = nsMPM.DirIO.get(nsMPM.pref_dir);
- 	menus_file.append(nsMPM.pref_file_menus);
- 	var servers_file = nsMPM.DirIO.get(nsMPM.pref_dir);
- 	servers_file.append(nsMPM.pref_file_servers);
- 	if ( servers_file.exists() && menus_file.exists() ) return '2.0.6';
- 
- 	if ( nsMPM.prefs.isPref('nsMPM.debug') ) return '2.0.4';
- 
- 	menus_file = nsMPM.DirIO.get(pref_dir_old);
- 	menus_file.append(pref_file_menus_old);
- 	servers_file = nsMPM.DirIO.get(pref_dir_old);
- 	servers_file.append(pref_file_servers_old);
- 	if ( servers_file.exists() || menus_file.exists() ) return '2.0.0';
- 
- 	if ( nsMPM.prefs.isPref('mpd_host') ) return '1.4.4';
- 	return mpmGetCurrentVersion();
- }
- 
- function mpmGetCurrentVersion() {
- 	var rdfs = Components.classes['@mozilla.org/rdf/rdf-service;1']
- 				.getService(Components.interfaces.nsIRDFService);
- 	var extension = rdfs.GetResource('urn:mozilla:item:Music_Player_Minion@code.google.com');
- 	var gExtensionDB = Components.classes['@mozilla.org/extensions/manager;1']
- 				.getService(Components.interfaces.nsIExtensionManager)
- 				.QueryInterface(Components.interfaces.nsIExtensionManager)
- 				.datasource;
- 
- 	// Version
- 	var versionArc = rdfs.GetResource(EM_NS('version'));
- 	var version = gExtensionDB.GetTarget(extension, versionArc, true);
- 	return version.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
- }
- 
- function mpmSetUpgraded(isUpgraded) {
- 	if ( typeof(isUpgraded) == 'boolean' ) nsMPM.prefs.set('upgraded',isUpgraded);
- 	else nsMPM.prefs.set('upgraded',false);
- }
- 
- function EM_NS(aProperty) {
-     return 'http://www.mozilla.org/2004/em-rdf#' + aProperty;
- }
- 
- function mpmSetCurrentVersion() {
- 	nsMPM.prefs.set('version',mpmGetCurrentVersion());
- }
- 
- // Upgrade dialog box functions
- mpmUpgrade.check = function(mpd) {
- 	try {
- 		var oldVersion = mpmGetPreviousVersion();
- 		if ( oldVersion == mpmGetCurrentVersion() ) {
- 			nsMPM.debug('No upgrades to do');
- 			return;
- 		}
- 
- 		nsMPM.debug('mpm preferences need to be upgraded ('+mpmGetPreviousVersion()+' != '+mpmGetCurrentVersion()+')');
- 		switch(oldVersion) {
- 			case '1.4.4':
- 				mpmSetUpgraded(mpmUpgrade144(mpd));
- 			break;
- 			case '2.0.0':
- 				mpmSetUpgraded(mpmUpgrade200(mpd));
- 			case '2.0.4':
- 				mpmSetUpgraded(mpmUpgrade204(mpd));
- 			case '2.0.6':
- 				mpmSetUpgraded(mpmUpgrade206(mpd));
- 			case '2.0.12':
- 				mpmSetUpgraded(true);
- 			break;
- 			default:
- 				nsMPM.debug('This version has nothing to upgrade ('+oldVersion+')');
- 				mpmSetUpgraded(true);
- 			break;
- 		}
- 		mpmCleanOldPrefs();
- 		mpmSetCurrentVersion();
- 		nsMPM.debug('Upgrade done');
- 	} catch(e) { nsMPM.debug(e); }
- }
- 
- mpmUpgrade.isUpgraded = function(reset) {
- 	var isUpgraded = nsMPM.prefs.get('upgraded',true);
- 	if ( typeof(reset) == 'boolean' && reset == true ) 	nsMPM.prefs.set('upgraded',false);
- 	return isUpgraded;
- }
- 
- mpmUpgrade.dialogInit = function(document){
- 	try {
- 		var rdfs = Components.classes['@mozilla.org/rdf/rdf-service;1'].
- 							  getService(Components.interfaces.nsIRDFService);
- 		var extension = rdfs.GetResource('urn:mozilla:item:Music_Player_Minion@code.google.com');
- 		var gExtensionDB = Components.classes['@mozilla.org/extensions/manager;1'].
- 						   getService(Components.interfaces.nsIExtensionManager).
- 						   QueryInterface(Components.interfaces.nsIExtensionManager).
- 						   datasource;
- 	
- 		var extensionsStrings = document.getElementById('extensionsStrings');
- 	
- 		// Name
- 		var nameArc = rdfs.GetResource(EM_NS('name'));
- 		var name = gExtensionDB.GetTarget(extension, nameArc, true);
- 		name = name.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
- 	
- 		// Version
- 		version = mpmGetCurrentVersion();
- 	
- 		// Description
- 		var descriptionArc = rdfs.GetResource(EM_NS('description'));
- 		var description = gExtensionDB.GetTarget(extension, descriptionArc, true);
- 		if (description)
- 		  description = description.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
- 	
- 		document.title = extensionsStrings.getFormattedString('aboutWindowTitle', [name]);
- 		var extensionName = document.getElementById('extensionName');
- 		extensionName.setAttribute('value', name);
- 		var extensionVersion = document.getElementById('extensionVersion');
- 		extensionVersion.setAttribute('value', version);
- 	
- 		var extensionDescription = document.getElementById('extensionDescription');
- 		extensionDescription.appendChild(document.createTextNode(description));
- 	
- 		var acceptButton = document.documentElement.getButton('accept');
- 		acceptButton.label = extensionsStrings.getString('aboutWindowCloseButton');
- 		nsMPM.debug('fin init');
- 	} catch(e){nsMPM.debug(e);}
- }
- 
- mpmUpgrade.doServer = function() {
- 	nsMPM.mpm_openDialog('chrome://minion/content/servers.xul', 'servers');
- }
- 
- mpmUpgrade.doSettings = function() {
- 	nsMPM.mpm_openDialog('chrome://minion/content/settings.xul', 'settings');
- }
- 
- mpmUpgrade.doAbout = function() {
- 	nsMPM.mpm_openDialog('chrome://minion/content/about/about.xul', 'about');
- }	
\ No newline at end of file
--- 0 ----
diff -c -r -N minion.orig//chrome/resource/mpmUtils.js minion.patched//chrome/resource/mpmUtils.js
*** minion.orig//chrome/resource/mpmUtils.js	2012-03-30 23:07:40.145062918 +0200
--- minion.patched//chrome/resource/mpmUtils.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,1246 ****
- /**
-  * Music Player Minion Copyright 2008, Chris Seickel
-  *
-  * This program is free software; you can redistribute it and/or modify it under
-  * the terms of the GNU General Public License as published by the Free Software
-  * Foundation; either version 2 of the License, or (at your option) any later
-  * version.
-  *
-  * This program is distributed in the hope that it will be useful, but WITHOUT
-  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-  * details.
-  *
-  * You should have received a copy of the GNU General Public License along with
-  * this program; if not, write to the Free Software Foundation, Inc., 51
-  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-  */
- var EXPORTED_SYMBOLS = ["nsMPM"];
- 
- Components.utils.import("resource://minion/mpmCommon.js");
- 
- nsMPM.observerService  = nsMPM.Cc["@mozilla.org/observer-service;1"]
- 						.getService(nsMPM.Ci.nsIObserverService);
- nsMPM.consoleService   = nsMPM.Cc["@mozilla.org/consoleservice;1"]
- 						.getService(nsMPM.Ci.nsIConsoleService);
- nsMPM.winw 			   = nsMPM.Cc["@mozilla.org/embedcomp/window-watcher;1"]
- 						.getService(nsMPM.Ci.nsIWindowWatcher);
- nsMPM.slidetimer 	   = nsMPM.Cc["@mozilla.org/timer;1"]
- 						.createInstance(nsMPM.Ci.nsITimer);
- nsMPM.translateService = nsMPM.Cc["@mozilla.org/intl/stringbundle;1"]
- 						.getService(nsMPM.Ci.nsIStringBundleService)
- 						.createBundle("chrome://minion/locale/strings.properties");
- nsMPM.env =				nsMPM.Cc["@mozilla.org/process/environment;1"].
- 						getService(nsMPM.Ci.nsIEnvironment);
- 
- nsMPM.getStringTime = function() {
- 	var today = new Date();
- 	var strDate = "";
- 	var t = 0;
- 	
- 	t = today.getHours();
- 	if ( t.toString().length == 1 ) strDate += '0';
- 	strDate += t +':';
- 	
- 	t = today.getMinutes();
- 	if ( t.toString().length == 1 ) strDate += '0';
- 	strDate += t +':';
- 
- 	t = today.getSeconds();
- 	if ( t.toString().length == 1 ) strDate += '0';
- 	strDate += t +'.';
- 	
- 	t = today.getMilliseconds();
- 	if ( t.toString().length == 1 ) strDate += '00';
- 	if ( t.toString().length == 2 ) strDate += '0';
- 	strDate += t;
- 	
- 	return strDate;
- }
- 
- nsMPM.debug = function (s) {
- 	let that = this;
- 	
- 	if ( typeof(that) == 'undefined' ) dump("that doesn't exists\n");
- 	if ( typeof(that.prefs) == 'undefined' ) dump("that.prefs doesn't exists\n");
- 	
- 	if ( that.prefs.get("debug", false) != true ) return;	
- 	try {
- 		var strDate = that.getStringTime();
- 		var f = 0;
- 		var str = "";
- 		if (s == null) s = "null passed to debug";
- 		if (typeof(s) == 'object') {
- 			for (x in s) {
- 				try {
- 					if ( f != 0 ) str += "\n             ";
- 					str += x + ': ' + s[x];
- 				} catch (e) {
- 					if ( f != 0 ) str += "\n             ";
- 					str += x + ': ERROR';
- 				}
- 				f=1;
- 			}
- 		} else if (typeof(str) == 'string') {
- 			var str = s;
- 		}
- 		if (typeof(str) == 'string' && str.length > 0) {
- 			dump(strDate + ' ' + str + "\n");
- 			//that.consoleService.logStringMessage(str)
- 		}
- 	} catch (e) {
- 		dump("error in debug!")
- 		dump(e);
- 		that.consoleService.logStringMessage("error in debug!")
- 	}
- }
- 
- nsMPM.Nz = function(obj, def) {
- 	if (typeof(obj) == 'undefined') {
- 		return (typeof(def) == 'undefined') ? null : def
- 	}
- 	return obj
- }
- 
- nsMPM.Sz = function(str) {
-     /* Prepare strings for mpd socket communications */
-     if (typeof(str) == "string")
-         return '"' + str.replace(/\"/g, '\\"') + '"'
-     return "''"
- }
- 
- nsMPM.smartsort = function(a,b) {
-     if (a.type != b.type) {
-         if (a.type>b.type) return 1
-         if (a.type<b.type) return -1
-     }
-     var column = "name"     
-     if (isNaN(a[column]+b[column])) {
-         var al = a[column].toLowerCase()
-         var bl = b[column].toLowerCase()
-         if (al>bl) return 1
-         if (al<bl) return -1
-         return 0
-     }
-     else { return a[column]-b[column]}
- }
- 
- nsMPM.urlReplace = function(s, item) {   
- 	let that = this;
- 
- 	if (that.Nz(item.file)) item.Path = item.file.split("/").slice(0,-1).join("/");
- 	// that.debug(item);
- 	for (x in item) {
- 		var re = new RegExp("{"+x+"}","ig");
- 		s = s.replace(re, that.fixedEncodeURI(item[x]));
- 	}
- 	s = s.replace(/{[^}]+}/g,"");
- 	return s;
- }
- 
- nsMPM.fixedEncodeURI = function(str) {
- 	// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/encodeURIComponent
- 	// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/encodeURI
- 	return encodeURI(str).replace(/!/g, '%21').replace(/'/g, '%27')
- 							  .replace(/\(/g, '%28').replace(/\)/g, '%29')
- 							  .replace(/\*/g, '%2A').replace(/\@/g, '%40')
- 							  .replace(/&/g, '%26').replace(/#/g, '%23');
- }
- 
- nsMPM.getFileContents = function(aURL) {
- 	let that = this;
- 	var ioService = that.Cc["@mozilla.org/network/io-service;1"].getService(that.Ci.nsIIOService);
- 	var scriptableStream = that.Cc["@mozilla.org/scriptableinputstream;1"].getService(that.Ci.nsIScriptableInputStream);
- 
- 	var channel = ioService.newChannel(aURL, null, null);
- 	var input = channel.open();
- 	scriptableStream.init(input);
- 	var str = scriptableStream.read(input.available());
- 	scriptableStream.close();
- 	input.close();
- 	return str;
- }
- 
- nsMPM.hmsFromSec = function(sec) {
- 	var hms = "0:00";
- 	try {
- 		sec = parseInt(sec);
- 	} catch (err) {
- 		return "0:00";
- 	}
- 	if (sec > 0) {
- 		var h = 0;
- 		if (sec >= 3600) {
- 			h = Math.floor(sec / 3600);
- 			sec = sec % 3600;
- 		}
- 		var m = Math.floor(sec / 60);
- 		var s = sec % 60;
- 		if (h > 0) {
- 			h = h + ":";
- 			if (m.toString().length == 1) m = "0" + m;
- 		} else h = "";
- 
- 		m = m + ":";
- 		if (s.toString().length == 1) s = "0" + s;
- 		hms = h + m + s;
- 	}
- 	return hms;
- }
- 
- nsMPM.prettyTime = function(sec, round) {
- 	let that = this;
- 	var tm = ""
- 	try {
- 		sec = parseInt(sec)
- 	} catch (err) {
- 		that.debug("prettyTime: " + err.description);
- 		sec = 0
- 	}
- 	if (sec > 0) {
- 		var d = Math.floor(sec / 86400)
- 		sec = sec % 86400
- 		var h = Math.floor(sec / 3600)
- 		sec = sec % 3600
- 		var m = Math.floor(sec / 60)
- 		var s = sec % 60
- 		var sep = ""
- 
- 		if (d > 0) {
- 			if (d > 1) tm = d + " " + that.translateService.GetStringFromName("days");
- 			else tm = d + " " + that.translateService.GetStringFromName("day");
- 			sep = ", ";
- 		}
- 
- 		if (h > 0) {
- 			tm += sep;
- 			if ( h > 1 ) {
- 				if (d > 0) tm += h + " " + that.translateService.GetStringFromName("hrs");
- 				else tm += h + " " + that.translateService.GetStringFromName("hours");
- 			} else {
- 				if (d > 0) tm += h + " " + that.translateService.GetStringFromName("hr");
- 				else tm += h + " " + that.translateService.GetStringFromName("hour");
- 			}
- 			sep = ", ";
- 		}
- 
- 		if (m > 0) {
- 			tm += sep;
- 			if ( m > 1 ) {
- 				if (d > 0) tm += m + " " + that.translateService.GetStringFromName("mins");
- 				else tm += m + " " + that.translateService.GetStringFromName("minutes");
- 			} else {
- 				if (d > 0) tm += m + " " + that.translateService.GetStringFromName("min");
- 				else tm += m + " " + that.translateService.GetStringFromName("minute");
- 			}
- 			sep = ", ";
- 		}
- 
- 		if (!that.Nz(round) && s > 0) {
- 			tm += sep;
- 			if ( s > 1 ) {
- 			if (d > 0) tm += s + " " + that.translateService.GetStringFromName("secs");
- 			else tm += s + " " + that.translateService.GetStringFromName("seconds");
- 			} else {
- 				if (d > 0) tm += s + " " + that.translateService.GetStringFromName("sec");
- 				else tm += s + " " + that.translateService.GetStringFromName("second");
- 			}
- 		}
- 	}
- 	return tm
- }
- 
- nsMPM.copyArray = function(oldArray) {
- 	if (typeof(oldArray) == 'object') {
- 		var l = oldArray.length
- 		var n = l
- 		var newArray = []
- 		if (l > 0) {
- 			do {
- 				newArray.push(oldArray[l - n])
- 			} while (--n)
- 		}
- 		return newArray
- 	} else
- 		return oldArray
- }
- 
- nsMPM.getAmazonArt = function(mpd, item, img) {
- 	let that = this;
- 	
- 	var art = "chrome://minion/content/images/album_blank.png";
- 	var search_url = that.urlReplace(
- 					"http://musicbrainz.org/ws/1/release/?type=xml&artist={Artist}&title={Album}&limit=1",
- 					item);
- 	if ( typeof(item.Album) != 'string' || typeof(item.Artist) != 'string' 
- 			|| item.Album == "" || item.Artist == "") {
- 		that.debug("Not enough info for search...")
- 		img.src = 'chrome://minion/content/images/album_blank_no_info.png';
- 		img.setAttribute("tooltiptext",that.translateService.GetStringFromName("track_no_info"));	
- 	} else {
- 		that.debug("searching Metabrainz...")
- 		if (typeof(nsMPM.mpd.cachedArt[search_url]) == 'string') {
- 			img.src = nsMPM.mpd.cachedArt[search_url];
- 			img.setAttribute("tooltiptext",nsMPM.mpd.cachedArt[search_url]);
- 		} else {
- 			var cb = function(data) {
- 				try {
- 					var asin = "";
- 					if (data != "") {
- 						var s = data.indexOf("<asin>") + 6;
- 						if (s > 6) {
- 							var e = data.indexOf("</asin>", s);
- 							if (e > 0) {
- 								asin = data.slice(s, e);
- 							}
- 							if (asin.length == 10 && asin != '          ') {
- 								base = "http://images.amazon.com/images/P/" + asin;
- 								art = base + ".01.MZZZZZZZ.jpg";
- 							}
- 						}
- 					}
- 					that.debug('applying art='+art);
- 					nsMPM.mpd.cachedArt[search_url] = art;
- 					img.src = art;
- 					img.setAttribute("tooltiptext",art);
- 					that.SaveImageToURL(item,art);
- 				} catch (e) {
- 					that.debug(e);
- 				}
- 			};
- 			that.fetch(search_url, cb);
- 		}
- 	}
- }
- 
- nsMPM.SaveImageToURL = function(item,url) {
- 	let that = this;
- 	
- 	try {
- 		that.debug('SaveImageToURL url=');
- 		that.debug(url);
- 		// we want to reject dummy requests
- 		var txt = new String(url);
- 		if (txt.indexOf('chrome://') == 0) return;
- 
- 		// unless specified, we don't save arts
- 		if ( parseInt(that.prefs.get("use_amazon_art",1)) != 2 ) {
- 			return;
- 		}
- 		
- 		// the source object we want to download
- 		var oSourceURL = that.Cc["@mozilla.org/network/io-service;1"]
- 			.getService(that.Ci.nsIIOService)
- 			.newURI(url, null, null);
- 		
- 		// if file:// we want to probe if it already exists
- 		var oTargetFile = that.Cc["@mozilla.org/file/local;1"]
- 			.createInstance(that.Ci.nsILocalFile);
- 		// use to create the destination object
- 		var ioService = that.Cc["@mozilla.org/network/io-service;1"]
- 			.getService(that.Ci.nsIIOService);
- 		
- 		var sTargetFile = that.urlReplace(that.prefs.get("save_art_url"), item);
- 		var oDestination = ioService.newURI(sTargetFile,null,null);
- 
- 		that.debug("Attempt to download url: "+url);
- 		that.debug("Attempt to save to file: "+sTargetFile);
- 
- 		// Probe if the file already exists
- 		if ( oDestination.scheme == 'file://' ) {		
- 			oTargetFile.initWithPath(oDestination.path);		
- 			if(oTargetFile.exists()) {
- 				that.debug("File already exists");
- 				return;
- 			} else {
- 				oTargetFile.create(0x00,0640);
- 			}
- 		}
- 
- 		// create a persist
- 		var persist = that.Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
- 			createInstance(that.Ci.nsIWebBrowserPersist);
- 
- 		// with persist flags if desired See nsIWebBrowserPersist page for more PERSIST_FLAGS.
- 		const nsIWBP = that.Ci.nsIWebBrowserPersist;
- 		// const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
- 		const flags = nsIWBP.PERSIST_FLAGS_NONE;
- 		persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_FROM_CACHE;
- 
- 		// do the save
- 		persist.saveURI(oSourceURL, null, null, null, null, oDestination);
- 
- 	} catch(e) { 
- 		that.debug(e); 
- 	}
- }
- 
- nsMPM.prefetchImageFromURL = function(url, callBack, arg) {
- 	let that = this;
- 	try {
- 		that.debug('Prefetch requested');
- 		var imgRequest = that.Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
- 						.createInstance();
- 		imgRequest.QueryInterface(that.Ci.nsIDOMEventTarget);
- 		imgRequest.QueryInterface(that.Ci.nsIXMLHttpRequest);
- 
- 		imgRequest.open("POST", url, true);
- 		imgRequest.onreadystatechange = function() {
- 			if (imgRequest.readyState == 4) {
- 				imgRequest.onreadystatechange = null;
- 				var status = imgRequest.status;
- 				imgRequest = null;
- 				callBack(status, arg, url);
- 			}
- 		};
- 		imgRequest.send("q="+(Math.random()*10000));
- 	} catch (e) { 
- 		// exception was raised, so we fallback to amazon if possible
- 		// that.debug(e);
- 		callBack(404, arg, url);
- 	}
- }
- 
- nsMPM.fetch = function(url, callBack, arg, getXML) {
- 	let that = this;
- 	try {
- 		var request = that.Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
- 		request.QueryInterface(that.Ci.nsIDOMEventTarget);
- 		request.QueryInterface(that.Ci.nsIXMLHttpRequest);
- 
- 		request.open("GET", url, true)
- 		request.onreadystatechange = function() {
- 			try{
- 				that.debug("state="+request.readyState);
- 				if (request.readyState == 4) {
- 					if (request.status == 200) {
- 						that.debug(request);
- 						if (that.Nz(getXML)) {
- 							callBack(request.responseXML, arg, request)
- 						} else {
- 							callBack(request.responseText, arg, request)
- 						}
- 						request.onreadystatechange = null
- 						request = null
- 					} else {
- 						that.debug("fetch("+request.status+")=> "+url)
- 						request.onreadystatechange = null
- 						request = null
- 					}
- 				}
- 			} catch(e){ that.debug(e); }
- 		}
- 		request.send("");
- 	} catch (e) { that.debug(e) }
- }
- 
- nsMPM.mpm_openDialog = function(url, id) {
- 	let that = this;
- 	var features = "chrome,dialog=yes,resizable=yes"
- 	if (id=="settings") features += ",titlebar,toolbar"
- 	var win = that.winw.openWindow(that.winw.activeWindow, url, that.Nz(id, url),features, null);
- }
- 
- nsMPM.openReuseByURL = function(url) {
- 	let that = this;
- 	var wm = null;
- 	try {
- 		wm = that.Cc["@mozilla.org/appshell/window-mediator;1"]
- 			.getService(that.Ci.nsIWindowMediator);
- 		
- 	} catch(e) {
- 		that.debug(e);
- 	}
- 	var browserEnumerator = wm.getEnumerator("navigator:browser");
- 	// Check each browser instance for our URL
- 	var found = false;
- 	try {
- 		while (!found && browserEnumerator.hasMoreElements()) {
- 			var browser = browserEnumerator.getNext();
- 			var browserInstance = browser.getBrowser();
- 
- 			// Check each tab of this browser instance
- 			var numTabs = browserInstance.tabContainer.childNodes.length;
- 			for (var index = 0; index < numTabs; index++) {
- 				var currentBrowser = browserInstance.getBrowserAtIndex(index);
- 				if (url == currentBrowser.currentURI.spec) {
- 					// The URL is already opened. Select this tab.
- 					browserInstance.selectedTab = browserInstance.tabContainer.childNodes[index];
- 					// Focus *this* browser
- 					browser.focus();
- 					browserInstance.focus();
- 					that.debug("browser already in tab");
- 					// wrapped is compulsory otherwise we can't right click on the statusbar
- 					// to display album details and perform queries.
- 					var win = currentBrowser.contentWindow.wrappedJSObject;
- 					found = true;
- 					break;
- 				}
- 			}
- 		}
- 		if (!found) {
- 			var openInTab = that.prefs.get("launch_in_browser", false);
- 			var recent = (openInTab) ? wm.getMostRecentWindow("navigator:browser") : false;
- 			if (recent) {
- 				recent.focus();
- 				browserInstance = recent.getBrowser();
- 				browserInstance.selectedTab = browserInstance.addTab(url);
- 				browserInstance.focus();
- 				var currentBrowser = browserInstance.getBrowserForTab(browserInstance.selectedTab);
- 				// wrapped is compulsory otherwise we can't right click on the statusbar
- 				// to display album details and perform queries.
- 				var win = currentBrowser.contentWindow.wrappedJSObject;
- 			} else {
- 				var win = that.winw.getWindowByName(url, null);
- 				if (!win) win = that.winw.openWindow(null, url, url, null, null);
- 				win.focus();
- 			}
- 		}
- 		return win;
- 	} catch (e) {
- 		that.debug(e);
- 	}
- 	return null;
- }
- 
- nsMPM.openReuseByAttribute = function(url, attrName) {
- 	let that = this;
- 
- 	var wm = that.Cc["@mozilla.org/appshell/window-mediator;1"].getService(that.Ci.nsIWindowMediator);
- 	attrName = that.Nz(attrName, 'mpm-unknown-tab')
- 	try {
- 		for (var found = false, 
- 			index = 0, 
- 			browserInstance = wm.getEnumerator('navigator:browser').getNext().getBrowser(); 
- 			index < browserInstance.mTabContainer.childNodes.length && !found; index++) {
- 			var currentTab = browserInstance.mTabContainer.childNodes[index];
- 			if (currentTab.hasAttribute(attrName)) {
- 				browserInstance.selectedTab = currentTab;
- 				browserInstance.focus();
- 				found = true;
- 			}
- 		}
- 		if (!found) {
- 			var browserEnumerator = wm.getEnumerator("navigator:browser");
- 			var browserInstance = browserEnumerator.getNext().getBrowser();
- 			var newTab = browserInstance.addTab(url);
- 			newTab.setAttribute(attrName, "xyz");
- 			browserInstance.selectedTab = newTab;
- 			browserInstance.focus();
- 		}
- 	} catch (e) {
- 		that.winw.openWindow(null, url, attrName, null, null)
- 	}
- }
- 
- nsMPM.guessTags = function(song) {
- 	let that = this;
- 	
- 	_artist = ""
- 	_album = ""
- 	_title = ""
- 	_track = ""
- 	track = that.Nz(song.Track, "")
- 	title = that.Nz(song.Title, "")
- 	artist = that.Nz(song.Artist, "")
- 	album = that.Nz(song.Album, "")
- 	try {
- 		myfile = song.file.match(/[^\/]+$/)[0].replace(/\.[a-zA-Z0-9]+$/, "")
- 		_title = myfile
- 		myfile = myfile.replace(/\(.*\)/g, "").replace(/_/g, " ")
- 		s = myfile.split("-")
- 		l = s.length
- 		
- 		for (var i=0;i<l;i++) {
- 			if (/^[0-9\.\/\s]+$/.test(s[i])) {
- 				_track = s.splice(i,1)
- 				if (typeof(_track) == 'string')
- 					_track = _track.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
- 				break
- 			}
- 		}
- 
- 		if (s.length > 0) _title = s.pop()
- 		if (s.length > 0) _artist = s.shift()
- 		if (s.length > 0) _album = s.join("-")
- 		
- 		if (track == "") song.Track = _track
- 		if (title == "") song.Title = _title.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
- 		if (artist == "") song.Artist = _artist.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
- 		if (album == "") song.Album = _album.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
- 	} catch (e) {that.debug(e)}
- 	return song
- }
- nsMPM.updateStatusBarAllStyles = function(wStorage) {
- 	let that = this;
- 	that.updateStatusBarStyles(wStorage);
- 	that.updateStatusBarElementsStyles(wStorage,'pref','launch',null);
- 	that.updateStatusBarElementsStyles(wStorage,'pref','playback',null);
- 	that.updateStatusBarElementsStyles(wStorage,'pref','currentsong',null);
- 	that.updateStatusBarElementsStyles(wStorage,'pref','playlist',null);
- 	that.updateStatusBarElementsStyles(wStorage,'pref','settings',null);
- }
- nsMPM.updateStatusBarElementsStyles = function (wStorage, domain, topic, hide){
- 	let that = this;
- 	if ( !topic || topic == '') {
- 		that.debug('Call to updateStatusBarElementsStyles with no topic');
- 		return;
- 	}
- 	switch (domain) {
- 		case 'force':
- 			switch(topic) {
- 				case 'playback':
- 					wStorage.document.getElementById('mpm_sb_controls').hidden = hide;
- 					wStorage.document.getElementById('mpm_sb_volume').hidden = hide;
- 				break;
- 				case 'currentsong':
- 					wStorage.document.getElementById('mpm_sb_currentsong').hidden = hide;
- 					wStorage.document.getElementById('mpm_sb_playlist').hidden = hide;
- 					wStorage.document.getElementById('mpm_sb_currentsongb').collapsed = hide;
- 					wStorage.document.getElementById('mpm_sb_playlistb').collapsed = hide;
- 				break;
- 				case 'playlist':
- 					wStorage.document.getElementById('sb_playlist_menu').collapsed = hide;
- 					wStorage.document.getElementById('sb_playlist_box').collapsed = hide;
- 
- 				break;
- 				default:
- 					that.debug('Call to updateStatusBarElementsStyles() with unknown domain:topic: '+domain+':'+topic);
- 				break;
- 			}
- 		break;
- 		case 'pref':
- 			switch(topic) {
- 				case 'launch':
- 					var h = that.prefs.get('sb_launch_hide', false);
- 					wStorage.document.getElementById('mpm_sb_launch').hidden = h;
- 				break;
- 				case 'playback':
- 					if  (that.mpd._socket == null) return;
- 					var h = that.prefs.get('sb_controls_hide', false);
- 					wStorage.document.getElementById('mpm_sb_controls').hidden = h;
- 					wStorage.document.getElementById('mpm_sb_volume').hidden = h;
- 				break;
- 				case 'currentsong':
- 					if  (that.mpd._socket == null) return;
- 					var h = that.prefs.get('sb_currentsong_hide', false);
- 					wStorage.document.getElementById('mpm_sb_currentsong').collapsed = h;
- 					wStorage.document.getElementById('mpm_sb_playlist').collapsed = !h;
- 					wStorage.document.getElementById('mpm_sb_box_resizer').collapsed = h;
- 					wStorage.document.getElementById('mpm_sb_currentsongb').collapsed = h;
- 					wStorage.document.getElementById('mpm_sb_playlistb').collapsed = !h;
- 					wStorage.document.getElementById('mpm_sb_box_resizerb').collapsed = h;
- 				break;
- 				case 'playlist':
- 					if  (that.mpd._socket == null) return;
- 					var menu = that.prefs.get('sb_playlist_menu', false);
- 					wStorage.document.getElementById('sb_playlist_menu').collapsed = !menu;
- 					wStorage.document.getElementById('sb_playlist_box').collapsed = menu;
- 				break;
- 				case 'settings':
- 					var h = that.prefs.get('sb_settings_hide', false);
- 					wStorage.document.getElementById('mpm_sb_servers').collapsed = h;
- 					wStorage.document.getElementById('mpm_sb_servers').hidden = h;
- 				break;
- 				default:
- 					that.debug('Call to updateStatusBarElementsStyles() with unknown domain:topic: '+domain+':'+topic);
- 				break;
- 			}
- 		break;
- 		default:
- 			that.debug('Call to updateStatusBarElementsStyles() with unknown domain:topic: '+domain+':'+topic);
- 		
- 	}
- }
- 
- nsMPM.updateStatusBarStyles = function(wStorage) {
- 	let that = this;
- 	var index = that.prefs.get("statusbar_position", 0);
- 	if (index < 0) index = 0;
- 	that.debug('status-bar index: '+index);	
- 	try
- 	{
- 		var statusBar = wStorage.document.getElementById("status-bar");
- 		var children = statusBar.childNodes;
- 
- 		if ( wStorage.statusbar == null )
- 			wStorage.statusbar = wStorage.document.getElementById("mpm_status-bar_controls");
- 		
- 		if ( wStorage.statusbar == null ) that.debug("mpm_status-bar_controls cannot be found")
-  
- 		try {
- 			statusBar.removeChild(wStorage.statusbar);
- 		} catch(e){that.debug("cannot remove status-bar item");}
- 
- 		if ( that.prefs.get('statusbar_hide',false) == false ) {
- 			// status-bar position
- 			if ((children.length == 0) || (index >= children.length)){
- 				statusBar.appendChild(wStorage.statusbar);
- 			} else {
- 				statusBar.insertBefore(wStorage.statusbar, children[index-1]);
- 			}
- 			
- 			// current song styles
- 			var newWidth = that.prefs.get('sb_song_width',150);
- 			that.debug("status-bar title width changed: "+ newWidth);
- 			wStorage.document.getElementById('mpm_sb_Titleb').setAttribute('width',newWidth);
- 			wStorage.document.getElementById('mpm_sb_Titleb').child.setAttribute('width',newWidth);
- 			wStorage.document.getElementById('mpm_sb_Title').setAttribute('width',newWidth);
- 			wStorage.document.getElementById('mpm_sb_Title').child.setAttribute('width',newWidth);
- 		} else {
- 			that.debug("Status-bar not displayed based on prefs");
- 		}
- 	} catch(e) {
- 		that.debug(e);
- 		that.debug('doc/document:');
- 		that.debug(doc);
- 	}
- }
- 
- nsMPM.chooseFolder = function(win, prefName) {
- 	let that = this;
- 	try {
- 		const nsIFilePicker = that.Ci.nsIFilePicker;
- 		const nsILocalFile = that.Ci.nsILocalFile;
- 
- 		var fp = that.Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
- 		var dnldMgr = that.Cc["@mozilla.org/download-manager;1"].getService(that.Ci.nsIDownloadManager);
- 
- 		var title = "My title";
- 		fp.init(win, title, nsIFilePicker.modeGetFolder);
- 		fp.appendFilters(nsIFilePicker.filterAll);
- 
- 		fp.displayDirectory = dnldMgr.defaultDownloadsDirectory;
- 
- 		if (fp.show() == nsIFilePicker.returnOK) {
- 			if ( typeof(prefName) != 'string' ) { that.debug('invalid prefName'); return; }
- 			if ( prefName.length < 1 ) { that.debug('invalid prefName'); return; }
- 			var forderPref = win.document.getElementById(prefName);
- 			var file = fp.fileURL;
- 			forderPref.value = file.spec;
- 		}
- 	} catch(e) { that.debug(e); }
- }
- 
- // update the UI from the prefs at load time
- nsMPM.updateCustomArtInterfacePref = function(doc) {
- 	let that = this;
- 
- 	try {
- 		var use_customPref = doc.getElementById("use_custom");
- 		var tbCoverUrl = doc.getElementById("tbCoverUrl");
- 		var btnBrowse = doc.getElementById("btnCustomBrowseLocalFile");
- 		
- 		if ( use_customPref.value == true ) {
- 			tbCoverUrl.disabled = false;
- 			btnBrowse.disabled = false;
- 		} else {
- 			tbCoverUrl.disabled = true;
- 			btnBrowse.disabled = true;
- 		}
- 	} catch(e) { that.debug(e); }
- }
- 
- // update the UI on user click
- nsMPM.updateCustomArtInterface = function(doc) {
- 	let that = this;
- 	try {
- 		var cbUseCustom = doc.getElementById("cbUseCustom");
- 		var tbCoverUrl = doc.getElementById("tbCoverUrl");
- 		var btnBrowse = doc.getElementById("btnCustomBrowseLocalFile");
- 
- 		if ( cbUseCustom.checked == true ) {
- 			tbCoverUrl.disabled = false;
- 			btnBrowse.disabled = false;
- 		} else {
- 			tbCoverUrl.disabled = true;
- 			btnBrowse.disabled = true;
- 		}
- 	} catch(e) { that.debug(e); }
- }
- nsMPM.updateIntervalInterfacePref = function(doc) {
- 	let that = this;
- 
- 	try {
- 		var adapt_intervalPref = doc.getElementById("adapt_interval");
- 		var tbUpdate = doc.getElementById("update");
- 		
- 		if ( adapt_intervalPref.value == true ) tbUpdate.disabled = true;
- 		else tbUpdate.disabled = false;
- 	} catch(e) { that.debug(e); }
- }
- nsMPM.updateIntervalInterface = function (doc) {
- 	let that = this;
- 
- 	try {
- 		var cbCheck_adapt = doc.getElementById("check_adapt");
- 		var tbUpdate = doc.getElementById("update");
- 
- 		if ( cbCheck_adapt.checked == true ) tbUpdate.disabled = true;
- 		else tbUpdate.disabled = false;
- 	} catch(e) { that.debug(e); }
- }
- nsMPM.updateStatusbarInterfacePref = function(doc) {	
- 	let that = this;
- 	try {
- 		var statusbar_hidePref = doc.getElementById("statusbar_hide");
- 		var cbLaunch = doc.getElementById("check_launch");
- 		var cbControls = doc.getElementById("check_ctrl");
- 		var cbCurrentSong = doc.getElementById("check_cs");
- 		var cbSettings = doc.getElementById("check_settings");
- 		var cbPlaylistMenu = doc.getElementById("check_playlist_menu");
- 		var lbPosition = doc.getElementById("label_position");
- 		var tbPosition = doc.getElementById("txt_statusbar_position");
- 		
- 		if ( statusbar_hidePref.value == true ){
- 			cbLaunch.disabled = cbControls.disabled = cbCurrentSong.disabled = cbSettings.disabled = cbPlaylistMenu.disabled = lbPosition.disabled = tbPosition.disabled = true;
- 		} else {
- 			cbLaunch.disabled = cbControls.disabled = cbCurrentSong.disabled = cbSettings.disabled = cbPlaylistMenu.disabled = lbPosition.disabled = tbPosition.disabled = false;
- 		}		
- 	} catch(e){ that.debug(e); }
- }
- nsMPM.updateStatusbarInterface = function (doc) {
- 	let that = this;
- 	try {
- 		var cbStatusbarHide = doc.getElementById("check_statusbar_hide");
- 		var cbLaunch = doc.getElementById("check_launch");
- 		var cbControls = doc.getElementById("check_ctrl");
- 		var cbCurrentSong = doc.getElementById("check_cs");
- 		var cbSettings = doc.getElementById("check_settings");
- 		var cbPlaylistMenu = doc.getElementById("check_playlist_menu");
- 		var lbPosition = doc.getElementById("label_position");
- 		var tbPosition = doc.getElementById("txt_statusbar_position");
- 		
- 		if ( cbStatusbarHide.checked == true ){
- 			cbLaunch.disabled = cbControls.disabled = cbCurrentSong.disabled = cbSettings.disabled = cbPlaylistMenu.disabled = lbPosition.disabled = tbPosition.disabled = true;
- 		} else {
- 			cbLaunch.disabled = cbControls.disabled = cbCurrentSong.disabled = cbSettings.disabled = cbPlaylistMenu.disabled = lbPosition.disabled = tbPosition.disabled = false;
- 		}		
- 	} catch(e){ that.debug(e); }	
- }
- nsMPM.updateDownloadInterface = function(doc){
- 	let that = this;
- 	try {
- 		var cbDlIntegrate = doc.getElementById("check_dl_integrate");
- 		var rDlActionAdd = doc.getElementById("rDlActionAdd");
- 		var rDlActionrepl = doc.getElementById("rDlActionRepl");
- 		var rDlAfterNothing = doc.getElementById("rDlAfterNothing");
- 		var rDlAfterPlayStop = doc.getElementById("rDlAfterPlayStop");
- 		var rDlAfterPlayNow = doc.getElementById("rDlAfterPlayNow");
- 		
- 		if ( cbDlIntegrate.checked == true )	{
- 			rDlAfterNothing.disabled = rDlAfterPlayStop.disabled = rDlAfterPlayNow.disabled = false;
- 			rDlActionrepl.disabled = rDlActionAdd.disabled = false;
- 		} else {
- 			rDlAfterNothing.disabled = rDlAfterPlayStop.disabled = rDlAfterPlayNow.disabled = true;
- 			rDlActionrepl.disabled = rDlActionAdd.disabled = true;
- 		}
- 	}catch(e){ that.debug(e); }
- }
- 
- nsMPM.updateDownloadInterfacePref = function(doc){
- 	let that = this;
- 	try {
- 		var dl_integratePref = doc.getElementById("dl_integrate");
- 		var rDlActionAdd = doc.getElementById("rDlActionAdd");
- 		var rDlActionrepl = doc.getElementById("rDlActionRepl");
- 		var rDlAfterNothing = doc.getElementById("rDlAfterNothing");
- 		var rDlAfterPlayStop = doc.getElementById("rDlAfterPlayStop");
- 		var rDlAfterPlayNow = doc.getElementById("rDlAfterPlayNow");
- 		
- 		if ( dl_integratePref.value == true )	{
- 			rDlAfterNothing.disabled = rDlAfterPlayStop.disabled = rDlAfterPlayNow.disabled = false;
- 			rDlActionrepl.disabled = rDlActionAdd.disabled = false;
- 		} else {
- 			rDlAfterNothing.disabled = rDlAfterPlayStop.disabled = rDlAfterPlayNow.disabled = true;
- 			rDlActionrepl.disabled = rDlActionAdd.disabled = true;
- 		}
- 	}catch(e){ that.debug(e); }
- }
- 
- nsMPM.updateAmazonInterfacePref = function(doc) {
- 	let that = this;
- 	try {
- 		var use_amazonPref = doc.getElementById("use_amazon");
- 		var tbSaveCoverUrl = doc.getElementById("tbSaveCoverUrl");
- 		var btnBrowse = doc.getElementById("btnAmazonBrowseLocalFile");
- 
- 		if ( use_amazonPref.value == 2 ) {
- 			tbSaveCoverUrl.disabled = false;
- 			btnBrowse.disabled = false;
- 		} else {
- 			tbSaveCoverUrl.disabled = true;
- 			btnBrowse.disabled = true;
- 		}
- 	} catch(e) { that.debug(e); }
- }
- 
- nsMPM.updateAmazonInterface = function(doc) {
- 	let that = this;
- 	try {
- 		var rgUseAmazon = doc.getElementById("rgUseAmazon");
- 		var tbSaveCoverUrl = doc.getElementById("tbSaveCoverUrl");
- 		var btnBrowse = doc.getElementById("btnAmazonBrowseLocalFile");
- 
- 		if ( rgUseAmazon.value == 2 ) {
- 			tbSaveCoverUrl.disabled = false;
- 			btnBrowse.disabled = false;
- 		} else {
- 			tbSaveCoverUrl.disabled = true;
- 			btnBrowse.disabled = true;
- 		}
- 	} catch(e) { that.debug(e); }
- }
- 
- nsMPM.togglePlaylistBar = function(doc) {
- 	let that = this;
- 
- 	var b = doc.getElementById("mpm_playlist_sb");
- 	var pl = doc.getElementById("mpm_mw_playlist_box");
- 	var s = doc.getElementById("mpm_playlist_splitter");
- 	if (!b.collapsed) pl.saveColumns();
- 	else pl.showCurrent();
- 	
- 	if (parseInt(b.height) < 1) {
- 		s.collapsed = !s.collapsed;
- 		b.collapsed = !b.collapsed;
- 		that.slideevent.incr = 10;
- 		that.slideevent.end = 110;
- 	} else {
- 		that.slideevent.incr = -10;
- 		that.slideevent.end = 0;
- 	}
- 	that.slideevent.doc = doc;
- 	that.slidetimer.initWithCallback(that.slideevent,100,that.Ci.nsITimer.TYPE_REPEATING_SLACK);
- }
- 
- nsMPM.prefObserver = function(prefName, changeAction) {
- 	this.action = changeAction
- 	this.register = function(){
- 		this._branch = nsMPM.prefs.branch;
- 		this._branch.QueryInterface(nsMPM.Ci.nsIPrefBranchInternal);
- 		this._branch.addObserver("", this, false);
- 	},
- 	this.unregister = function(){
- 		if (!this._branch)
- 			return;
- 		this._branch.removeObserver("", this);
- 	},
- 	this.observe = function(aSubject, aTopic, aData){
- 		if (aTopic != "nsPref:changed")
- 			return;
- 		// aSubject is the nsIPrefBranch we're observing (after appropriate QI)
- 		// aData is the name of the pref that's been changed (relative to aSubject)
- 		if (aData == prefName) this.action()
- 	}
- }
- 
- nsMPM.prefs = {
- 	branch : Components.classes["@mozilla.org/preferences-service;1"]
- 			.getService(Components.interfaces.nsIPrefService)
- 			.getBranch("extensions.mpm."),
- 	get : function(strPref, def) {
- 		try{
- 			switch (this.branch.getPrefType(strPref)) {
- 				case this.branch.PREF_STRING :
- 					return this.branch.getCharPref(strPref);
- 				case this.branch.PREF_INT :
- 					return this.branch.getIntPref(strPref);
- 				case this.branch.PREF_BOOL :
- 					return this.branch.getBoolPref(strPref);
- 				default :
- 					def = nsMPM.Nz(def)
- 					this.set(strPref, def);
- 					return def;
- 			}
- 		} catch(e){ nsMPM.debug(e); }
- 		return 'undefined';
- 	},
- 	isPref : function (strPref) {
- 		try {
- 			if ( !strPref ) return false;
- 			if ( this.branch.getPrefType(strPref) != this.branch.PREF_INVALID ) return true;
- 			return false;
- 		} catch(e) { 
- 			nsMPM.debug(e);
- 			return false; 
- 		}
- 	},
- 	getObserver : function (prefName, prefAction) {
- 		var po = new nsMPM.prefObserver(prefName, prefAction)
- 		po.register()
- 		return po
- 	},
- 	clear : function(strPref) {
- 		try {
- 			this.branch.clearUserPref(strPref);
- 		} catch(e) { return; }
- 	},
- 	set : function(strPref, val) {
- 		switch (this.branch.getPrefType(strPref)) {
- 			case this.branch.PREF_STRING :
- 				this.branch.setCharPref(strPref, val);
- 				break;
- 			case this.branch.PREF_INT :
- 				this.branch.setIntPref(strPref, val);
- 				break;
- 			case this.branch.PREF_BOOL :
- 				this.branch.setBoolPref(strPref, val);
- 				break;
- 			default :
- 				if (typeof(val) != 'undefined') {
- 					switch (typeof(val)) {
- 						case 'string' :
- 							this.branch.setCharPref(strPref, val);
- 							break;
- 						case 'number' :
- 							this.branch.setIntPref(strPref, val);
- 							break;
- 						case 'boolean' :
- 							this.branch.setBoolPref(strPref, val);
- 							break;
- 						default :
- 							this.branch.setCharPref(strPref, val.toSource());
- 							break;
- 					}
- 				}
- 		}
- 	}
- }
- nsMPM.slideevent = {
- 	incr : 0,
- 	end : 0,
- 	doc : null,
- 	notify: function(slidetimer) {		
- 		if (this.end < 1) this.end = 0;
- 		if ( this.incr == 0 ) {
- 			// nsMPM.debug("canceled"+this.incr+"-"+this.end);
- 			slidetimer.cancel();
- 			return;
- 		}
- 		try {
- 			var b = this.doc.getElementById("mpm_playlist_sb");
- 			// nsMPM.debug("slideevent: incr="+this.incr+", end="+this.end+", b.height="+b.height+", b.boxObject.height="+b.boxObject.height);
- 			b.height = parseInt(b.height) + this.incr;
- 		} catch(e) {
- 			nsMPM.debug(e);
- 			slidetimer.cancel();
- 			return;
- 		}
- 		if (this.incr > 0) {
- 			if (b.height >= this.end) slidetimer.cancel();
- 		} else {
- 			if (b.height <= this.end) {
- 				slidetimer.cancel();
- 				b.collapsed = !b.collapsed;
- 				var s = this.doc.getElementById("mpm_playlist_splitter");
- 				s.collapsed = !s.collapsed;
- 			}
- 		}
- 	}
- }
- nsMPM.winStorage = function(win,doc) {
- 	if ( typeof(win) == 'undefinied' || typeof(doc) == 'undefined') return
- 	nsMPM.instance_count++;
- 	this.instance = nsMPM.instance_count;
- 	this.obs = null;
- 	this.obsVol = null;
- 	this.csPrefObserver = null;
- 	this.window = win;
- 	this.document = doc;
- 	this.mpm = null;
- 	this.statusbar = null;
- }
- 
- nsMPM.resizeHandler = {
- 	bResizing : false,
- 	startPosX : null,
- 	panelElem : null,
- 	lastWidth : null,
- 	minWidth : 25,
- 	startPanelWidth: null,
- 	win: null,
- 	
- 	onMouseMove: function(event){
- 		try{
- 			if (!nsMPM.resizeHandler.bResizing) return;
- 			var deltaX = event.screenX - nsMPM.resizeHandler.startPosX;
- 			
- 			var newWidth = 1*nsMPM.resizeHandler.startPanelWidth + deltaX;
- 			if (newWidth > nsMPM.resizeHandler.minWidth) {
- 				nsMPM.resizeHandler.panelElem.setAttribute('width', newWidth);
- 				nsMPM.resizeHandler.panelElem.child.setAttribute('width', newWidth);
- 				nsMPM.resizeHandler.lastWidth = newWidth;
- 			}
- 		} catch(e){nsMPM.debug(e);}
- 	},
- 	onMouseDown: function(win,event){
- 		/* the "win" is important to listen the mouse mvts globally */
- 		try{
- 			if (nsMPM.resizeHandler.bResizing) return;
- 			nsMPM.resizeHandler.bResizing = true;
- 			nsMPM.resizeHandler.startPosX = event.screenX;
- 			nsMPM.resizeHandler.panelElem  = event.target.previousSibling.lastChild;
- 			nsMPM.resizeHandler.startPanelWidth = nsMPM.resizeHandler.panelElem.getAttribute('width');
- 			win.addEventListener("mouseup", nsMPM.resizeHandler.onMouseUp, false);
- 			win.addEventListener("mousemove", nsMPM.resizeHandler.onMouseMove, false);
- 			nsMPM.resizeHandler.win = win;
- 		} catch(e){nsMPM.debug(e);}
- 	},
- 	onMouseUp: function(event){
- 		try {
- 			nsMPM.resizeHandler.bResizing = false;
- 			if ( nsMPM.resizeHandler.startPanelWidth != nsMPM.resizeHandler.lastWidth
- 				&& nsMPM.resizeHandler.lastWidth != null ) {
- 				if ( nsMPM.resizeHandler.lastWidth < nsMPM.resizeHandler.minWidth )
- 					nsMPM.resizeHandler.lastWidth = nsMPM.resizeHandler.minWidth;
- 				nsMPM.prefs.set('sb_song_width', nsMPM.resizeHandler.lastWidth);
- 			}
- 			if ( nsMPM.resizeHandler.win ) {
- 				nsMPM.resizeHandler.win.removeEventListener("mouseup",nsMPM.resizeHandler.onMouseUp,false);
- 				nsMPM.resizeHandler.win.removeEventListener("mousemove",nsMPM.resizeHandler.onMouseMove,false);
- 			}
- 		} catch(e){nsMPM.debug(e);}
- 	}
- }
- nsMPM.handleDowloadURL = function(urlObj){
- 	let that = this;
- 	try {
- 		var action = 'add';
- 		var lastsong = that.mpd.playlistlength;
- 		
- 		if ( that.prefs.get('dl.action',1) == 2) action = 'replace';
- 		if ( that.processDowloadURL(urlObj, action) ) {
- 			var after = that.prefs.get('dl.after',0);
- 			if ( after == 0 ) return; // do nothing
- 
- 			if ( after == 1 && that.mpd.state == 'stop' ) { // play if stopped
- 				if ( action == 'replace') that.mpd.doCmd('play');
- 				else that.mpd.doCmd('play '+lastsong);
- 			}
- 
- 			if ( after == 2 ) { // play now
- 				if ( action == 'replace') that.mpd.doCmd('play');
- 				else that.mpd.doCmd('play '+lastsong);
- 			}
- 		}
- 	} catch(e){ that.debug(e); }
- }
- 
- nsMPM.processDowloadURL = function(urlObj, action){
- 	let that = this;
- 	var url = urlObj.spec;
- 	if ( typeof(action) == 'undefined' ) action = 'add';
- 	that.debug('processDowloadURL('+urlObj.spec+','+action+')');
- 	
- 	function retrieveData(stream){
- 		try {
- 			if (!stream) return null;
- 			var size = 0;
- 			var file_data = "";
- 			var bstream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
- 			bstream.setInputStream(stream);
- 			while((size = bstream.available())) file_data += bstream.readBytes(size);
- 			return file_data;
- 		} catch(e){ that.debug(e); }
- 		return null;
- 	}
- 	try {
- 		if ( urlObj.fileExtension ){
- 			switch(urlObj.fileExtension.toLocaleLowerCase()){
- 				case "mp3" :
- 					if ( action == 'replace') that.mpd.doCmd('clear');
- 					that.mpd.doCmd('add "' + url + '"');
- 					return 1;
- 					break;
- 				case "ogg" :
- 					if ( action == 'replace') that.mpd.doCmd('clear');
- 					that.mpd.doCmd('add "' + url + '"');
- 					return 1;
- 					break;
- 				case "wav" :
- 					if ( action == 'replace') that.mpd.doCmd('clear');
- 					that.mpd.doCmd('add "' + url + '"');
- 					return 1;
- 					break;
- 				case "flac" :
- 					if ( action == 'replace') that.mpd.doCmd('clear');
- 					that.mpd.doCmd('add "' + url + '"');
- 					return 1;
- 					break;
- 				case "aac" :
- 					if ( action == 'replace') that.mpd.doCmd('clear');
- 					that.mpd.doCmd('add "' + url + '"');
- 					return 1;
- 					break;
- 				case "mod" :
- 					if ( action == 'replace') that.mpd.doCmd('clear');
- 					that.mpd.doCmd('add "' + url + '"');
- 					return 1;
- 					break;
- 				case "wma" :
- 					if ( action == 'replace') that.mpd.doCmd('clear');
- 					that.mpd.doCmd('add "' + url + '"');
- 					return 1;
- 					break;
- 			}
- 			
- 		}
- 		// these files require processing and local download
- 		var ioserv = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
- 		var channel = ioserv.newChannel(url, 0, null);
- 		var stream = channel.open();
- 		if (channel instanceof Components.interfaces.nsIHttpChannel && channel.responseStatus != 200) {
- 			that.debug("Failed to retrieve element: "+url);
- 			return false;
- 		} else {
- 			try {
- 				var contenttype = '';
- 				if ( typeof(channel.contentType) != 'undefined') contenttype = channel.contentType;
- 				else channel.getResponseHeader('Content-Type');
- 				if ( contenttype ){
- 					switch(contenttype){
- 						case "audio/x-scpls" :
- 							return that.mpd.load_pls_stream(retrieveData(stream), action);
- 						break;
- 						case "audio/x-mpegurl" :
- 							return that.mpd.load_m3u_stream(retrieveData(stream), action);
- 						break;
- 						case "application/xspf+xml" :
- 							try {
- 								var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
- 								var xml = parser.parseFromStream(stream, null, -1, "application/xml");
- 								return that.mpd.load_xspf_stream(xml, action);
- 							} catch(e){ that.debug(e); }
- 							return false;
- 						break;
- 					}
- 				}
- 			} catch(e){ that.debug(e); }
- 			// in case the server did not reported proper mime type but the extension matched (maybe)
- 			switch (url.substr(-4).toLocaleLowerCase()) {
- 				case ".pls" :
- 					return that.mpd.load_pls_stream(retrieveData(stream), action);
- 				break;
- 				case ".m3u" :
- 					return that.mpd.load_m3u_stream(retrieveData(stream), action);
- 				break;
- 				case "xspf" :
- 					try {
- 						var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
- 						var xml = parser.parseFromStream(stream, null, -1, "application/xml");
- 						return that.mpd.load_xspf_stream(xml, action);
- 					} catch(e){ that.debug(e); }
- 					return false;
- 				break;
- 			}
- 			that.debug("The specified URL isn't supported: "+url);
- 		}
- 	} catch(e){ that.debug(e); }
- 	return false;
- }
- // dependent js modules
- // declare holder in mpmCommon.js
- if (nsMPM.mpmMenu == null) Components.utils.import("resource://minion/mpmMenu.js",nsMPM);
- if (nsMPM.mpd == null) Components.utils.import("resource://minion/mpd.js",nsMPM);
- if (nsMPM.mpmUpgrade == null ) Components.utils.import("resource://minion/mpmUpgrade.js",nsMPM);
--- 0 ----
diff -c -r -N minion.orig//chrome/resource/trees.js minion.patched//chrome/resource/trees.js
*** minion.orig//chrome/resource/trees.js	2012-03-30 23:07:40.149062918 +0200
--- minion.patched//chrome/resource/trees.js	1970-01-01 01:00:00.000000000 +0100
***************
*** 1,466 ****
- /**    Music Player Minion  Copyright 2008, Chris Seickel
- *
- *      This program is free software; you can redistribute it and/or modify
- *      it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *      MA 02110-1301, USA.
- */
- 
- Components.utils.import("resource://minion/mpmUtils.js");
- EXPORTED_SYMBOLS = ["arrayView", "playlistView", "folderView"]
- 
- 
- function customTreeView () {
-     this.getRowCount = function() {return this.rs.length},
-     this.rs = []
-     this.db = []
-     this.treeBox = null
-     this.rowCount = 0
-     this.get = function (row) {return this.rs[row]}
-     this.canDrop = function (index, orientation ) {return false}
-     this.cycleCell = function (row, col ) {}
-     this.cycleHeader = function (col ) {}
-     this.drop = function (row, orientation ) {}
-     this.getCellProperties = function (row, col, props ) {
-         try {
-             var item = nsMPM.Nz(this.get(row))
-             if (item) {
-                 var t = item.type
-                 var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
- 
-                 props.AppendElement(aserv.getAtom(col.id))
-                 if (t == 'directory' && nsMPM.mpd.updating_db) {
-                     props.AppendElement(aserv.getAtom(col.id + "_updating"))
-                 }
-                 else {
-                     props.AppendElement(aserv.getAtom(col.id + "_" + t))
-                     if (nsMPM.mpd.song && nsMPM.Nz(item.Pos, -1) == nsMPM.mpd.song) {
-                         if (col.id == 'Title' && nsMPM.mpd.state != 'stop') {
-                             props.AppendElement(aserv.getAtom(nsMPM.mpd.state + "_currentsong"))
-                         }
-                         props.AppendElement(aserv.getAtom("currentsong"))
-                     }
-                 }
-                 aserv = null
-             }
-         }
-         catch (e) {
-             nsMPM.debug(e)
-             nsMPM.debug(item)
-         }
-     }
-     this.getCellText = function(R, C){
-         var item = this.get(R)
-         if (!nsMPM.Nz(item)) return "";
-         switch (C.id) {
-             case "Pos":
-                 if (item.type != 'file') return ""
-                 var p = item.Pos
-                 if (!p) p = nsMPM.Nz(nsMPM.mpd.pl_lookup[item.file])
-                 return (p) ? (parseInt(p) + 1) + "." : "";
-                 break;
-             case "Time":
-                 return (item.Time) ? nsMPM.hmsFromSec(item.Time) : "";
-                 break;
-             default:
-                 return (item[C.id]);
-                 break;
-         }
- 	return "";
-     }
-     this.getCellValue = function (row, col ) {return this.rs[row]}
-     this.getColumnProperties = function (col, properties ) {}
-     this.getImageSrc  = function (row, col ) {return ''}
-     this.getLevel = function  (index ) {return 0}
-     this.getParentIndex  = function (rowIndex ) {return -1}
-     this.getProgressMode  = function (row, col ) {return 3}
-     this.getRowProperties = function(index, properties){
-         try {
-             var item = this.get(index)
-             var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
-             props.AppendElement(aserv.getAtom(item.type))
-             aserv = null
-         }
-         catch (e) {
-         }
-     }
-     this.hasNextSibling = function (rowIndex, afterIndex ) {return true}
-     this.isContainer  = function (index ) {return false}
-     this.isContainerEmpty  = function (index ) {return false}
-     this.isContainerOpen  = function (index ) {return false}
-     this.isEditable  = function (row, col ) {return false}
-     this.isSelectable  = function (row, col ) {return false}
-     this.isSeparator  = function (index ) {return false}
-     this.isSorted  = function ( ) {return false}
-     this.performAction  = function (action ) {}
-     this.performActionOnCell  = function (action, row, col ) {}
-     this.performActionOnRow  = function (action, row ) {}
-     this.selectionChanged  = function ( ) {}
-     this.setCellText  = function (row, col, value ) {}
-     this.setCellValue  = function (row, col, value ) {}
-     this.setTree  = function ( tree ) {
-         this.treeBox = tree
-     }
-     this.toggleOpenState  = function (index ) {}
- }
- 
- 
- function arrayView(dbArray) {
-     this.rowCount = dbArray.length
-     this.rs = dbArray
- 	this.getCounts = function () {
- 		var files = [x for each (x in dbArray) if (x.type=='file')]
- 		var time = 0
- 		for each (f in files) {time += Math.parseInt(f.Time)}
- 		var text = f.length + " "+nsMPM.translateService.GetStringFromName("tracks")+", " + nsMPM.prettyTime(time)
- 	}
- }
- arrayView.prototype = new customTreeView
- 
- function playlistView(){
-     this.getPointer = function (idx) {
-         return {
-             type: 'pointer',
-             index: idx,
-             Title: 'Loading...',
-             pointer: "loading...",
-             isContainer: false,
-             isOpen: false
-         }
-     }
-     this.load = function (db, expanded){
-         if (!nsMPM.Nz(expanded)) {
-             var rc = db.length
-             var rs = new Array()
-             rs.length = rc
-             if (rc) {
-                 var n = rc
-                 do {
-                     var i = rc - n
-                     rs[i] = this.getPointer(i)
- 
-                 }
-                 while (--n)
-             }
-         }
-         else {
-             var rc = db.length * 3
-             var rs = new Array()
-             rs.length = rc
-             if (rc) {
-                 var n = rc
-                 var idx = 0
-                 do {
-                     rs[rc - n] = this.getPointer(idx)
-                     rs[rc - n].isOpen = true
-                     --n
-                     rs[rc - n] = {
-                         index: idx,
-                         type: 'Album',
-                         Prefix: nsMPM.translateService.GetStringFromName("from")+" ",
-                         isContainer: false
-                     }
-                     --n
-                     rs[rc - n] = {
-                         index: idx,
-                         type: 'Artist',
-                         Prefix: nsMPM.translateService.GetStringFromName("by")+" ",
-                         isContainer: false
-                     }
-                     idx++
-                 }
-                 while (--n)
-             }
-         }
-         if (this.treeBox) {
-             var chg = rs.length-this.rs.length
-             var n = (chg < 0) ? 1 : this.rs.length
-             this.treeBox.rowCountChanged(n-1, chg)
-             this.treeBox.invalidate()
-             this.treeBox.scrollToRow(0)
-         }
-         this.db = db;
-         this.rs = rs;
-         this.rowCount = this.rs.length;
-     }
-     this.addItem = function (idx, expanded) {
-         var i = this.rs.length
-         var nw = this.getPointer(idx)
-         this.rs[i] = nw
-         if (expanded) {
-             this.rs[i].isOpen = true
-             this.rs[i+1] = {
-                 index: idx,
-                 type: 'Album',
-                 Prefix: nsMPM.translateService.GetStringFromName("from")+" ",
-                 isContainer: false
-             }
-             this.rs[i+2] = {
-                 index: idx,
-                 type: 'Artist',
-                 Prefix: nsMPM.translateService.GetStringFromName("by")+" ",
-                 isContainer: false
-             }
-             this.treeBox.rowCountChanged(i-1, 3)
-         }
-         else {
-             this.treeBox.rowCountChanged(i-1, 1)
-         }
-     }
-     this.removeItems = function (count) {
-         var n = this.rs.length
-         for (var i = 0; i < count; i++) {
-             --n
-             if (n > 0) {
-                 if (!this.isContainer(n)) {
-                     var n = this.getParentIndex(n)
-                 }
-             }
-             else {
-                 n = 0
-                 i = count
-             }
-         }
-         this.treeBox.rowCountChanged(n-1, n-this.rs.length)
-         this.rs.length = n
-     }
-     this.get = function (row) {
-         var cur = nsMPM.Nz(this.rs[row])
-         if (!cur) {
-             //this.treeBox.rowCountChanged(row, -1)
-             return {type: 'unknown', pos: null, time: null, Title: 'ERROR!'}
-         }
-         if (cur.type == 'pointer') {
-             return nsMPM.Nz(this.db[cur.index], cur)
-         }
-         else {
-             var item = nsMPM.Nz(this.db[cur.index], cur)
-             return {
-                 type: cur.type,
-                 index: cur.index,
-                 time: null,
-                 pos: null,
-                 Title: cur.Prefix+item[cur.type]
-             }
-         }
-     }
-     this.getPointer = function (idx) {
-         return {
-             type: 'pointer',
-             index: idx,
-             Title: 'Loading...',
-             pointer: "loading...",
-             isContainer: true,
-             isOpen: false
-         }
-     }
-     this.isContainerOpen = function(row){
-         return this.rs[row].isOpen
-     }
-     this.isContainer = function(row){
-         return (this.rs[row].isContainer)
-     }
-     this.getParentIndex = function(idx){
-         if (this.rs[idx].isContainer) return -1
-         do {
-             --idx
-         } while (!this.rs[idx].isContainer && idx > -1)
-         return idx
-     }
-     this.getLevel = function(row){
-         try {
-             return (this.rs[row].isContainer) ? 0 : 1
-         }
-         catch (e) {
-             nsMPM.debug(e)
-             return 0
-         }
-     }
-     this.hasNextSibling = function(row, afterIndex){
-         var item = this.rs[row]
-         var after = this.rs[afterIndex]
-         if (item.type == 'pointer') {
-             return (after.type == 'pointer')
-         }
-         return !(after.type == 'pointer')
-     }
-     this.toggleOpenState = function(row){
-         try {
-             if (this.rs[row].isOpen) {
-                 this.rs[row].isOpen = false
-                 this.rs.splice(parseInt(row) + 1, 2)
-                 this.treeBox.rowCountChanged(row + 1, -2)
-             }
-             else {
-                 var item = this.get(row)
-                 var art = {
-                     index: item.Pos,
-                     type: 'Artist',
-                     Prefix: nsMPM.translateService.GetStringFromName("by")+" ",
-                     isContainer: false
-                 }
-                 var alb = {
-                     index: item.Pos,
-                     type: 'Album',
-                     Prefix: nsMPM.translateService.GetStringFromName("from")+" ",
-                     isContainer: false
-                 }
-                 this.rs[row].isOpen = true
-                 this.rs.splice(row+1, 0, alb, art)
-                 this.treeBox.rowCountChanged(row, 2)
-                 //this.rowCount = this.rs.length
-             }
-         }
-         catch (e) {
-             nsMPM.debug(e)
-         }
-     }
-     this.getRowProperties = function(row, props){
-         try {
-             var item = this.rs[row]
-             if (item.type != 'unknown') {
-                 var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
-                 props.AppendElement(aserv.getAtom(item.type))
-                 var P = (parseInt(item.index) % 2) ? 'odd' : 'even'
-                 var R = (row % 2) ? 'odd' : 'even'
-                 if (P != R) {
-                     props.RemoveElement(aserv.getAtom(R))
-                     props.AppendElement(aserv.getAtom(P))
-                 }
-                 aserv = null
-             }
-         }
-         catch (e) {
-         }
-     }
- }
- playlistView.prototype = new customTreeView
- 
- 
- function folderView(dbArray, rsArray) {
-     var rs = (nsMPM.Nz(rsArray))
-     if (!rs) rs = [x for each (x in dbArray) if (x.level == 0)].sort()
-     var view = {
-         db: dbArray,
-         rs: rs,
-         treeBox: null,
-         selection: null,
-         get rowCount () {return this.rs.length},
-         getLevel: function  (index ) {
-             return this.rs[index].level
-         },
-         getParentIndex : function (rowIndex ) {
-             var parent = this.rs[rowIndex].parent
-             if (parent == "") return -1
-             for (var idx=rowIndex-1;idx>0;idx--) {
-                 if (this.rs[idx].name == parent) return idx;
-             }
-             return -1
-         },
-         hasNextSibling: function (idx, after) {
-             var thisLevel = this.getLevel(idx);
-             for (var t = after + 1; t < this.rs.length; t++) {
-                 var nextLevel = this.getLevel(t)
-                 if (nextLevel == thisLevel) return true;
-                 else if (nextLevel < thisLevel) return false;
-             }
- 			return false;
-         },
-         isContainer: function (index ) {
-             return true
-         },
-         isContainerEmpty : function (index ) {
-             return (this.rs[index].children < 1)
-         },
-         isContainerOpen : function (index ) {
-             if (index+1 >= this.rowCount) return false
-             return (this.rs[index+1].level > this.rs[index].level)
-         },
- 
-         toggleOpenState : function (index ) {
-             var leaf = this.rs[index]
-             if (this.isContainerOpen(index)) {
-         var i = 1
-         while (this.rs[index + i].level > leaf.level) {i++}
-         --i
-                 this.rs.splice(index+1, i)
-                 this.treeBox.rowCountChanged(index + 1, -i)
-             }
-             else {
-                 var children = [x for each (x in this.db) if (x.parent == leaf.name)]
-                 this.rs = this.rs.slice(0, index+1).concat(children, this.rs.slice(index+1))
-                 this.treeBox.rowCountChanged(index+1, children.length)
-             }
-         },
-         canDrop: function (index, orientation ) {return false},
-         cycleCell: function (row, col ) {},
-         cycleHeader: function (col ) {},
-         drop: function (row, orientation ) {},
-         getCellProperties: function (row, col, props ) {
-             try {
-                 var item = this.rs[row]
-                 var t = item.type
-                 var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
- 
-                 props.AppendElement(aserv.getAtom(col.id))
-                 if (t == 'directory' && nsMPM.mpd.updating_db) {
-                     props.AppendElement(aserv.getAtom(col.id + "_updating"))
-                 }
-                 else {
-                     props.AppendElement(aserv.getAtom(col.id + "_" + t))
-                     if (item.name == nsMPM.mpd.file) {
-                         if (col.id == 'Title' && nsMPM.mpd.state != 'stop') {
-                             props.AppendElement(aserv.getAtom(nsMPM.mpd.state + "_currentsong"))
-                         }
-                         props.AppendElement(aserv.getAtom("currentsong"))
-                     }
-                 }
-                 aserv = null
-             }
-             catch (e) {
-                 nsMPM.debug(e)
-             }
-         },
-         getCellText: function(R, C){
-             return this.rs[R].Title
-         },
-         getCellValue: function (row, col ) {return this.rs[row]},
-         getColumnProperties: function (col, properties ) {},
-         getImageSrc : function (row, col ) {return ''},
-         getProgressMode : function (row, col ) {return 3},
-         getRowProperties: function(index, properties){
-             try {
-                 var item = this.rs[index]
-                 var aserv = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
-                 props.AppendElement(aserv.getAtom(item.type))
-                 aserv = null
-             }
-             catch (e) {
-             }
-         },
-         isEditable : function (row, col ) {return false},
-         isSelectable : function (row, col ) {return false},
-         isSeparator : function (index ) {return false},
-         isSorted : function ( ) {return false},
-         performAction : function (action ) {},
-         performActionOnCell : function (action, row, col ) {},
-         performActionOnRow : function (action, row ) {},
-         selectionChanged : function ( ) {},
-         setCellText : function (row, col, value ) {},
-         setCellValue : function (row, col, value ) {},
-         setTree : function ( tree ) {
-             this.treeBox = tree
-         }
-     }
-     return view
- }
--- 0 ----
diff -c -r -N minion.orig//defaults/preferences/prefs.js minion.patched//defaults/preferences/prefs.js
*** minion.orig//defaults/preferences/prefs.js	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//defaults/preferences/prefs.js	2011-12-31 10:58:22.000000000 +0100
***************
*** 0 ****
--- 1,8 ----
+ 
+ //pref("toolkit.defaultChromeURI", "chrome://minion/content/minion.xul");
+ //pref("browser.dom.window.dump.enabled", true);
+ //pref("javascript.options.showInConsole", true);
+ //pref("javascript.options.strict", true);
+ //pref("nglayout.debug.disable_xul_cache", true);
+ //pref("nglayout.debug.disable_xul_fastload", true);
+ pref("extensions.mpm.server", "localhost:6600:");
diff -c -r -N minion.orig//defaults/preferences/prefs.xr minion.patched//defaults/preferences/prefs.xr
*** minion.orig//defaults/preferences/prefs.xr	1970-01-01 01:00:00.000000000 +0100
--- minion.patched//defaults/preferences/prefs.xr	2011-12-31 10:58:22.000000000 +0100
***************
*** 0 ****
--- 1,8 ----
+ 
+ pref("toolkit.defaultChromeURI", "chrome://minion/content/minion.xul");
+ //pref("browser.dom.window.dump.enabled", true);
+ //pref("javascript.options.showInConsole", true);
+ //pref("javascript.options.strict", true);
+ //pref("nglayout.debug.disable_xul_cache", true);
+ //pref("nglayout.debug.disable_xul_fastload", true);
+ pref("extensions.mpm.server", "localhost:6600:");
diff -c -r -N minion.orig//install.rdf minion.patched//install.rdf
*** minion.orig//install.rdf	2012-03-30 23:07:17.953063997 +0200
--- minion.patched//install.rdf	2012-03-30 23:08:19.585061001 +0200
***************
*** 5,11 ****
  
    <rdf:Description about="urn:mozilla:install-manifest">
      <id>Music_Player_Minion@code.google.com</id>
!     <version>__mpm_version__</version>
      <type>2</type>
      <optionsURL>chrome://minion/content/servers.xul</optionsURL>
      <iconURL>chrome://minion/content/images/logo.png</iconURL>
--- 5,11 ----
  
    <rdf:Description about="urn:mozilla:install-manifest">
      <id>Music_Player_Minion@code.google.com</id>
!     <version>2.1.3</version>
      <type>2</type>
      <optionsURL>chrome://minion/content/servers.xul</optionsURL>
      <iconURL>chrome://minion/content/images/logo.png</iconURL>
***************
*** 17,23 ****
        <rdf:Description>
          <id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</id>
          <minVersion>3.0</minVersion>
!         <maxVersion>3.6.*</maxVersion>
        </rdf:Description>
      </targetApplication>
  
--- 17,23 ----
        <rdf:Description>
          <id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</id>
          <minVersion>3.0</minVersion>
!         <maxVersion>14.0a1</maxVersion>
        </rdf:Description>
      </targetApplication>
  
***************
*** 30,35 ****
--- 30,36 ----
      <contributor>Aurélien Requiem</contributor>
      <contributor>Alexandre Moore (icons)</contributor>
      <contributor>Tango Desktop Project (icons)</contributor>
+     <contributor>Niko Berger</contributor>
  
      <translator>Aurélien Requiem (fr-FR)</translator>
      <translator>Roberto Ripio (es-ES)</translator>
