home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February / PCWorld_2008-02_cd.bin / temacd / songbird / Songbird_0.4_windows-i686.exe / components / sbDownloadDeviceHelper.js < prev    next >
Text File  |  2007-12-21  |  12KB  |  372 lines

  1. /*
  2. //
  3. // BEGIN SONGBIRD GPL
  4. //
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright(c) 2005-2008 POTI, Inc.
  8. // http://songbirdnest.com
  9. //
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the "GPL").
  12. //
  13. // Software distributed under the License is distributed
  14. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  15. // express or implied. See the GPL for the specific language
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc.,
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. //
  23. // END SONGBIRD GPL
  24. //
  25. */
  26.  
  27. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  28. Components.utils.import("resource://app/components/sbProperties.jsm");
  29. Components.utils.import("resource://app/components/ArrayConverter.jsm");
  30.  
  31. const Ci = Components.interfaces;
  32. const Cc = Components.classes;
  33. const Cr = Components.results;
  34. const Cu = Components.utils;
  35. const CE = Components.Exception;
  36.  
  37. const PREF_DOWNLOAD_MUSIC_FOLDER       = "songbird.download.music.folder";
  38. const PREF_DOWNLOAD_MUSIC_ALWAYSPROMPT = "songbird.download.music.alwaysPrompt";
  39.  
  40. /**
  41.  * Our super-smart heuristic for determining if the download folder is valid.
  42.  */
  43. function folderIsValid(folder) {
  44.   try {
  45.     return folder && folder.isDirectory();
  46.   }
  47.   catch (e) {
  48.   }
  49.   return false;
  50. }
  51.  
  52. /**
  53.  * Returns an nsILocalFile or null if the path is bad.
  54.  */
  55. function makeFile(path) {
  56.   var file = Cc["@mozilla.org/file/local;1"].
  57.              createInstance(Ci.nsILocalFile);
  58.   try {
  59.     file.initWithPath(path);
  60.   }
  61.   catch (e) {
  62.     return null;
  63.   }
  64.   return file;
  65. }
  66.  
  67. /**
  68.  * Returns a file url for the path.
  69.  */
  70. function makeFileURL(path)
  71. {
  72.   // Can't use the IOService because we have callers off of the main thread...
  73.   // Super lame hack instead.
  74.   return "file://" + path;
  75. }
  76.  
  77. function sbDownloadDeviceHelper()
  78. {
  79.   this._mainLibrary = Cc["@songbirdnest.com/Songbird/library/Manager;1"]
  80.                         .getService(Ci.sbILibraryManager).mainLibrary;
  81. }
  82.  
  83. sbDownloadDeviceHelper.prototype =
  84. {
  85.   classDescription: "Songbird Download Device Helper",
  86.   classID:          Components.ID("{576b6833-15d8-483a-84d6-2fbd329c82e1}"),
  87.   contractID:       "@songbirdnest.com/Songbird/DownloadDeviceHelper;1",
  88.   QueryInterface:   XPCOMUtils.generateQI([Ci.sbIDownloadDeviceHelper])
  89. }
  90.  
  91. sbDownloadDeviceHelper.prototype.downloadItem =
  92. function sbDownloadDeviceHelper_downloadItem(aMediaItem)
  93. {
  94.   var downloadFileURL = this._safeDownloadFileURL();
  95.   if (!downloadFileURL) {
  96.     return;
  97.   }
  98.  
  99.   let uriArray           = Cc["@mozilla.org/array;1"]
  100.                              .createInstance(Ci.nsIMutableArray);
  101.   let propertyArrayArray = Cc["@mozilla.org/array;1"]
  102.                              .createInstance(Ci.nsIMutableArray);
  103.  
  104.   let item;
  105.   if (aMediaItem.library.equals(this._mainLibrary)) {
  106.     item = aMediaItem;
  107.   }
  108.   else {
  109.     this._addItemToArrays(aMediaItem, uriArray, propertyArrayArray);
  110.     let items = this._mainLibrary.batchCreateMediaItems(uriArray,
  111.                                                         propertyArrayArray,
  112.                                                         true);
  113.     item = items.queryElementAt(0, Ci.sbIMediaItem);
  114.   }
  115.  
  116.   this._setDownloadDestination([item], downloadFileURL);
  117.   this.getDownloadMediaList().add(item);
  118. }
  119.  
  120. sbDownloadDeviceHelper.prototype.downloadSome =
  121. function sbDownloadDeviceHelper_downloadSome(aMediaItems)
  122. {
  123.   var downloadFileURL = this._safeDownloadFileURL();
  124.   if (!downloadFileURL) {
  125.     return;
  126.   }
  127.  
  128.   let uriArray           = Cc["@mozilla.org/array;1"]
  129.                              .createInstance(Ci.nsIMutableArray);
  130.   let propertyArrayArray = Cc["@mozilla.org/array;1"]
  131.                              .createInstance(Ci.nsIMutableArray);
  132.  
  133.   var items = [];
  134.   while (aMediaItems.hasMoreElements()) {
  135.     let item = aMediaItems.getNext();
  136.     if (item.library.equals(this._mainLibrary)) {
  137.       items.push(item);
  138.     }
  139.     else {
  140.       this._addItemToArrays(item, uriArray, propertyArrayArray);
  141.     }
  142.   }
  143.  
  144.   if (uriArray.length > 0) {
  145.     let addedItems = this._mainLibrary.batchCreateMediaItems(uriArray,
  146.                                                              propertyArrayArray,
  147.                                                              true);
  148.     for (let i = 0; i < addedItems.length; i++) {
  149.       items.push(addedItems.queryElementAt(i, Ci.sbIMediaItem));
  150.     }
  151.   }
  152.  
  153.   this._setDownloadDestination(items, downloadFileURL);
  154.   this.getDownloadMediaList().addSome(ArrayConverter.enumerator(items));
  155. }
  156.  
  157. sbDownloadDeviceHelper.prototype.downloadAll =
  158. function sbDownloadDeviceHelper_downloadAll(aMediaList)
  159. {
  160.   var downloadFileURL = this._safeDownloadFileURL();
  161.   if (!downloadFileURL) {
  162.     return;
  163.   }
  164.  
  165.   let uriArray           = Cc["@mozilla.org/array;1"]
  166.                              .createInstance(Ci.nsIMutableArray);
  167.   let propertyArrayArray = Cc["@mozilla.org/array;1"]
  168.                              .createInstance(Ci.nsIMutableArray);
  169.  
  170.   var items = [];
  171.   var isForeign = aMediaList.library.equals(this._mainLibrary);
  172.   for (let i = 0; i < aMediaList.length; i++) {
  173.     var item = aMediaList.getItemByIndex(i);
  174.     if (isForeign) {
  175.       this._addItemToArrays(item, uriArray, propertyArrayArray);
  176.     }
  177.     else {
  178.       items.push(item);
  179.     }
  180.   }
  181.  
  182.   if (uriArray.length > 0) {
  183.     let addedItems = this._mainLibrary.batchCreateMediaItems(uriArray,
  184.                                                              propertyArrayArray,
  185.                                                              true);
  186.     for (let i = 0; i < addedItems.length; i++) {
  187.       items.push(addedItems.queryElementAt(i, Ci.sbIMediaItem));
  188.     }
  189.   }
  190.  
  191.   this._setDownloadDestination(items, downloadFileURL);
  192.   this.getDownloadMediaList().addSome(ArrayConverter.enumerator(items));
  193. }
  194.  
  195. sbDownloadDeviceHelper.prototype.getDownloadMediaList =
  196. function sbDownloadDeviceHelper_getDownloadMediaList()
  197. {
  198.   if (!this._downloadDevice) {
  199.     var devMgr = Cc["@songbirdnest.com/Songbird/DeviceManager;1"]
  200.                    .getService(Ci.sbIDeviceManager);
  201.     if (devMgr) {
  202.       var downloadCat = "Songbird Download Device";
  203.       if (devMgr.hasDeviceForCategory(downloadCat)) {
  204.         this._downloadDevice = devMgr.getDeviceByCategory(downloadCat)
  205.                                      .QueryInterface(Ci.sbIDownloadDevice);
  206.       }
  207.     }
  208.   }
  209.   return this._downloadDevice ? this._downloadDevice.downloadMediaList : null;
  210. }
  211.  
  212. sbDownloadDeviceHelper.prototype.getDefaultMusicFolder =
  213. function sbDownloadDeviceHelper_getDefaultMusicFolder()
  214. {
  215.   const dirService = Cc["@mozilla.org/file/directory_service;1"].
  216.                      getService(Ci.nsIDirectoryServiceProvider);
  217.   const platform = Cc["@mozilla.org/xre/app-info;1"].
  218.                    getService(Ci.nsIXULRuntime).
  219.                    OS;
  220.  
  221.   var musicDir;
  222.   switch (platform) {
  223.     case "WINNT":
  224.       musicDir = dirService.getFile("Pers", {});
  225.       musicDir.append("My Music");
  226.       break;
  227.  
  228.     case "Darwin":
  229.       musicDir = dirService.getFile("Music", {});
  230.       break;
  231.  
  232.     case "Linux":
  233.       musicDir = dirService.getFile("Home", {});
  234.       musicDir.append("Music");
  235.  
  236.       if (!folderIsValid(musicDir)) {
  237.         musicDir = musicDir.parent;
  238.         musicDir.append("music");
  239.       }
  240.       break;
  241.  
  242.     default:
  243.       // Fall through and use the Desktop below.
  244.       break;
  245.   }
  246.  
  247.   // Make sure that the directory exists and is writable.
  248.   if (!folderIsValid(musicDir)) {
  249.     // Great, default to the Desktop... This should work on all OS's.
  250.     musicDir = dirService.getFile("Desk", {});
  251.  
  252.     // We should never get something bad here, but just in case...
  253.     if (!folderIsValid(musicDir)) {
  254.       Cu.reportError("Desktop directory is not a directory!");
  255.       throw Cr.NS_ERROR_FILE_NOT_DIRECTORY;
  256.     }
  257.   }
  258.  
  259.   return musicDir;
  260. }
  261.  
  262. sbDownloadDeviceHelper.prototype.getDownloadFolder =
  263. function sbDownloadDeviceHelper_getDownloadFolder()
  264. {
  265.   const Application = Cc["@mozilla.org/fuel/application;1"].
  266.                       getService(Ci.fuelIApplication);
  267.   const prefs = Application.prefs;
  268.  
  269.   var downloadFolder;
  270.   if (prefs.has(PREF_DOWNLOAD_MUSIC_FOLDER)) {
  271.     var downloadPath = prefs.get(PREF_DOWNLOAD_MUSIC_FOLDER).value;
  272.     downloadFolder = makeFile(downloadPath);
  273.   }
  274.  
  275.   if (!folderIsValid(downloadFolder)) {
  276.     // The pref was either bad or empty. Use (and write) the default.
  277.     downloadFolder = this.getDefaultMusicFolder();
  278.     prefs.setValue(PREF_DOWNLOAD_MUSIC_FOLDER, downloadFolder.path);
  279.   }
  280.  
  281.   const alwaysPrompt = prefs.getValue(PREF_DOWNLOAD_MUSIC_ALWAYSPROMPT, false);
  282.   if (!alwaysPrompt) {
  283.     return downloadFolder;
  284.   }
  285.  
  286.   const sbs = Cc["@mozilla.org/intl/stringbundle;1"].
  287.               getService(Ci.nsIStringBundleService);
  288.   const strings =
  289.     sbs.createBundle("chrome://songbird/locale/songbird.properties");
  290.   const title =
  291.     strings.GetStringFromName("prefs.main.musicdownloads.chooseTitle");
  292.  
  293.   const wm = Cc["@mozilla.org/appshell/window-mediator;1"].
  294.              getService(Ci.nsIWindowMediator);
  295.   const mainWin = wm.getMostRecentWindow("Songbird:Main");
  296.  
  297.   // Need to prompt, launch the filepicker.
  298.   const folderPicker = Cc["@mozilla.org/filepicker;1"].
  299.                        createInstance(Ci.nsIFilePicker);
  300.   folderPicker.init(mainWin, title, Ci.nsIFilePicker.modeGetFolder);
  301.   folderPicker.displayDirectory = downloadFolder;
  302.  
  303.   if (folderPicker.show() != Ci.nsIFilePicker.returnOK) {
  304.     // This is our signal that the user cancelled the dialog. Some folks won't
  305.     // care, but most will.
  306.     throw new CE("User canceled the download dialog.", Cr.NS_ERROR_ABORT);
  307.   }
  308.  
  309.   downloadFolder = folderPicker.file;
  310.  
  311.   prefs.setValue(PREF_DOWNLOAD_MUSIC_FOLDER, downloadFolder.path);
  312.   return downloadFolder;
  313. }
  314.  
  315. sbDownloadDeviceHelper.prototype._safeDownloadFileURL =
  316. function sbDownloadDeviceHelper__safeDownloadFileURL()
  317. {
  318.   // This function returns null if the user cancels the dialog.
  319.   try {
  320.     return makeFileURL(this.getDownloadFolder().path);
  321.   }
  322.   catch (e if e.result == Cr.NS_ERROR_ABORT) {
  323.   }
  324.   return "";
  325. }
  326.  
  327. sbDownloadDeviceHelper.prototype._addItemToArrays =
  328. function sbDownloadDeviceHelper__addItemToArrays(aMediaItem,
  329.                                                  aURIArray,
  330.                                                  aPropertyArrayArray)
  331. {
  332.   aURIArray.appendElement(aMediaItem.contentSrc, false);
  333.  
  334.   var dest   = SBProperties.createArray();
  335.   var source = aMediaItem.getProperties();
  336.   for (let i = 0; i < source.length; i++) {
  337.     var prop = source.getPropertyAt(i);
  338.     if (prop.id != SBProperties.contentSrc) {
  339.       dest.appendElement(prop, false);
  340.     }
  341.   }
  342.  
  343.   var target = aMediaItem.library.guid + "," + aMediaItem.guid;
  344.   dest.appendProperty(SBProperties.downloadStatusTarget, target);
  345.  
  346.   aPropertyArrayArray.appendElement(dest, false);
  347. }
  348.  
  349. sbDownloadDeviceHelper.prototype._setDownloadDestination =
  350. function sbDownloadDeviceHelper__setDownloadDestination(aItems,
  351.                                                         aDownloadPath)
  352. {
  353.   for each (var item in aItems) {
  354.     try {
  355.       item.setProperty(SBProperties.destination, aDownloadPath);
  356.     }
  357.     catch (e) {
  358.       // We're not allowed to set the download destination on remote media items
  359.       // so that call may fail. The remoteAPI should unwrap all items and lists
  360.       // *before* handing them to us, so throw the error with a slightly more
  361.       // helpful message.
  362.       throw new CE("Download destination could not be set on this media item:\n"
  363.                    + "  " + item + "\nIs it actually a remote media item?",
  364.                    e.result);
  365.     }
  366.   }
  367. }
  368.  
  369. function NSGetModule(compMgr, fileSpec) {
  370.   return XPCOMUtils.generateModule([sbDownloadDeviceHelper]);
  371. }
  372.