home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Freelog 112
/
FreelogNo112-NovembreDecembre2012.iso
/
Multimedia
/
Songbird
/
Songbird_2.0.0-2311_windows-i686-msvc8.exe
/
components
/
sbDownloadDeviceHelper.js
< prev
next >
Wrap
Text File
|
2012-06-08
|
18KB
|
509 lines
/*
//
// BEGIN SONGBIRD GPL
//
// This file is part of the Songbird web player.
//
// Copyright(c) 2005-2008 POTI, Inc.
// http://songbirdnest.com
//
// This file may be licensed under the terms of of the
// GNU General Public License Version 2 (the "GPL").
//
// Software distributed under the License is distributed
// on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
// express or implied. See the GPL for the specific language
// governing rights and limitations.
//
// You should have received a copy of the GPL along with this
// program. If not, go to http://www.gnu.org/licenses/gpl.html
// or write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// END SONGBIRD GPL
//
*/
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://app/jsmodules/sbProperties.jsm");
Components.utils.import("resource://app/jsmodules/ArrayConverter.jsm");
Components.utils.import("resource://app/jsmodules/FolderUtils.jsm");
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cr = Components.results;
const Cu = Components.utils;
const CE = Components.Exception;
const PREF_DOWNLOAD_FOLDER = {audio: "songbird.download.music.folder",
video: "songbird.download.video.folder"};
const PREF_DOWNLOAD_ALWAYSPROMPT = {audio: "songbird.download.music.alwaysPrompt",
video: "songbird.download.video.alwaysPrompt"};
const _MFM_GET_MANAGED_PATH_OPTIONS = Ci.sbIMediaFileManager.MANAGE_MOVE |
Ci.sbIMediaFileManager.MANAGE_COPY |
Ci.sbIMediaFileManager.MANAGE_RENAME;
/**
* \brief Get the name of the platform we are running on.
* \return The name of the OS platform. (ie. Windows).
* \retval Windows_NT Running under Windows.
* \retval Darwin Running under Darwin/OS X.
* \retval Linux Running under Linux.
* \retval SunOS Running under Solaris.
*/
function getPlatformString()
{
try {
var sysInfo =
Components.classes["@mozilla.org/system-info;1"]
.getService(Components.interfaces.nsIPropertyBag2);
return sysInfo.getProperty("name");
}
catch (e) {
dump("System-info not available, trying the user agent string.\n");
var user_agent = navigator.userAgent;
if (user_agent.indexOf("Windows") != -1)
return "Windows_NT";
else if (user_agent.indexOf("Mac OS X") != -1)
return "Darwin";
else if (user_agent.indexOf("Linux") != -1)
return "Linux";
else if (user_agent.indexOf("SunOS") != -1)
return "SunOS";
return "";
}
}
/**
* Our super-smart heuristic for determining if the download folder is valid.
*/
function folderIsValid(folder) {
try {
return folder && folder.isDirectory();
}
catch (e) {
}
return false;
}
/**
* Returns an nsILocalFile or null if the path is bad.
*/
function makeFile(path) {
var file = Cc["@mozilla.org/file/local;1"].
createInstance(Ci.nsILocalFile);
// Ensure all paths are lowercase for Windows.
// See bug #7178.
var actualPath = path;
if(getPlatformString() == "Windows_NT") {
actualPath = actualPath.toLowerCase();
}
try {
file.initWithPath(actualPath);
}
catch (e) {
return null;
}
return file;
}
/**
* Returns a file url for the path.
*/
function makeFileURL(path)
{
// Can't use the IOService because we have callers off of the main thread...
// Super lame hack instead.
// Ensure all paths are lowercase for Windows.
// See bug #7178.
var actualPath = path;
if(getPlatformString() == "Windows_NT") {
actualPath = actualPath.toLowerCase();
}
return "file://" + actualPath;
}
function sbDownloadDeviceHelper()
{
this._mainLibrary = Cc["@songbirdnest.com/Songbird/library/Manager;1"]
.getService(Ci.sbILibraryManager).mainLibrary;
}
sbDownloadDeviceHelper.prototype =
{
classDescription: "Songbird Download Device Helper",
classID: Components.ID("{576b6833-15d8-483a-84d6-2fbd329c82e1}"),
contractID: "@songbirdnest.com/Songbird/DownloadDeviceHelper;1",
QueryInterface: XPCOMUtils.generateQI([Ci.sbIDownloadDeviceHelper])
}
sbDownloadDeviceHelper.prototype.downloadItem =
function sbDownloadDeviceHelper_downloadItem(aMediaItem)
{
var downloadFolder = this._getDownloadFolder_nothrow(aMediaItem.contentType);
if (!downloadFolder) {
return;
}
let uriArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
.createInstance(Ci.nsIMutableArray);
let propertyArrayArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
.createInstance(Ci.nsIMutableArray);
let item;
if (aMediaItem.library.equals(this._mainLibrary)) {
item = aMediaItem;
}
else {
this._addItemToArrays(aMediaItem, uriArray, propertyArrayArray);
let items = this._mainLibrary.batchCreateMediaItems(uriArray,
propertyArrayArray,
true);
item = items.queryElementAt(0, Ci.sbIMediaItem);
}
// Pass the downloadFolder as the 'media-folder' option for the
// Media File Manager. The MFM will then put the file in the
// user's preferred folder (or possibly a subfolder thereof)
this._setDownloadDestinationIfNotSet([item],
{'media-folder': downloadFolder});
this._checkAndRemoveExistingItem(item);
this.getDownloadMediaList().add(item);
}
sbDownloadDeviceHelper.prototype.downloadSome =
function sbDownloadDeviceHelper_downloadSome(aMediaItems)
{
let uriArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
.createInstance(Ci.nsIMutableArray);
let propertyArrayArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
.createInstance(Ci.nsIMutableArray);
var items = [];
var foundTypes = {};
while (aMediaItems.hasMoreElements()) {
let item = aMediaItems.getNext();
if (item.library.equals(this._mainLibrary)) {
items.push(item);
}
else {
this._checkAndRemoveExistingItem(item);
this._addItemToArrays(item, uriArray, propertyArrayArray);
}
// Keep track of which media types are present. This
// will be used below to get the download folders for
// these media types:
foundTypes[item.contentType] = true;
}
// Get the user's preferred download folder for each media type
// in the item list and set up Media File Manager options with
// those folders. The MFM will then sort the files into the
// respective folders (or possibly subfolders thereof). Do this
// before creating the media items in case the user is prompted
// to choose a folder and clicks cancel:
mfmFolders = {};
try {
for (let contentType in foundTypes) {
let folder = this.getDownloadFolder(contentType);
if (folder) {
mfmFolders["media-folder:" + contentType] = folder;
}
}
}
catch (e if e.result == Cr.NS_ERROR_ABORT) {
return;
}
if (uriArray.length > 0) {
let addedItems = this._mainLibrary.batchCreateMediaItems(uriArray,
propertyArrayArray,
true);
for (let i = 0; i < addedItems.length; i++) {
items.push(addedItems.queryElementAt(i, Ci.sbIMediaItem));
}
}
this._setDownloadDestinationIfNotSet(items, mfmFolders);
this.getDownloadMediaList().addSome(ArrayConverter.enumerator(items));
}
sbDownloadDeviceHelper.prototype.downloadAll =
function sbDownloadDeviceHelper_downloadAll(aMediaList)
{
let uriArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
.createInstance(Ci.nsIMutableArray);
let propertyArrayArray = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
.createInstance(Ci.nsIMutableArray);
var items = [];
var foundTypes = {};
var isForeign = aMediaList.library.equals(this._mainLibrary);
for (let i = 0; i < aMediaList.length; i++) {
var item = aMediaList.getItemByIndex(i);
if (isForeign) {
this._checkAndRemoveExistingItem(item);
this._addItemToArrays(item, uriArray, propertyArrayArray);
}
else {
items.push(item);
}
// Keep track of which media types are present. This
// will be used below to get the download folders for
// these media types:
foundTypes[item.contentType] = true;
}
// Get the user's preferred download folder for each media type
// in the item list and set up Media File Manager options with
// those folders. The MFM will then sort the files into the
// respective folders (or possibly subfolders thereof). Do this
// before creating the media items in case the user is prompted
// to choose a folder and clicks cancel.
mfmFolders = {};
try {
for (let contentType in foundTypes) {
let folder = this.getDownloadFolder(contentType);
if (folder) {
mfmFolders["media-folder:" + contentType] = folder;
}
}
}
catch (e if e.result == Cr.NS_ERROR_ABORT) {
return;
}
if (uriArray.length > 0) {
let addedItems = this._mainLibrary.batchCreateMediaItems(uriArray,
propertyArrayArray,
true);
for (let i = 0; i < addedItems.length; i++) {
items.push(addedItems.queryElementAt(i, Ci.sbIMediaItem));
}
}
this._setDownloadDestinationIfNotSet(items, mfmFolders);
this.getDownloadMediaList().addSome(ArrayConverter.enumerator(items));
}
sbDownloadDeviceHelper.prototype.getDownloadMediaList =
function sbDownloadDeviceHelper_getDownloadMediaList()
{
if (!this._downloadDevice) {
var devMgr = Cc["@songbirdnest.com/Songbird/DeviceManager;1"]
.getService(Ci.sbIDeviceManager);
if (devMgr) {
var downloadCat = "Songbird Download Device";
if (devMgr.hasDeviceForCategory(downloadCat)) {
this._downloadDevice = devMgr.getDeviceByCategory(downloadCat)
.QueryInterface(Ci.sbIDownloadDevice);
}
}
}
return this._downloadDevice ? this._downloadDevice.downloadMediaList : null;
}
sbDownloadDeviceHelper.prototype.getDefaultDownloadFolder =
function sbDownloadDeviceHelper_getDefaultDownloadFolder(aContentType)
{
var mediaDir = FolderUtils.getDownloadFolder(aContentType);
// We should never get something bad here, but just in case...
if (!folderIsValid(mediaDir)) {
Cu.reportError("Desktop directory is not a directory!");
throw Cr.NS_ERROR_FILE_NOT_DIRECTORY;
}
return mediaDir;
}
sbDownloadDeviceHelper.prototype.getDownloadFolder =
function sbDownloadDeviceHelper_getDownloadFolder(aContentType)
{
const Application = Cc["@mozilla.org/fuel/application;1"].
getService(Ci.fuelIApplication);
const prefs = Application.prefs;
var downloadPath;
if (prefs.has(PREF_DOWNLOAD_FOLDER[aContentType])) {
downloadPath = prefs.get(PREF_DOWNLOAD_FOLDER[aContentType]).value;
}
var downloadFolder;
if (downloadPath) {
downloadFolder = makeFile(downloadPath);
}
else {
// The pref was empty. Use (and write) the default.
downloadFolder = this.getDefaultDownloadFolder(aContentType);
if (downloadFolder) {
prefs.setValue(PREF_DOWNLOAD_FOLDER[aContentType], downloadFolder.path);
}
}
const alwaysPrompt = prefs.getValue(PREF_DOWNLOAD_ALWAYSPROMPT[aContentType], false);
if (folderIsValid(downloadFolder) && !alwaysPrompt) {
return downloadFolder;
}
const sbs = Cc["@mozilla.org/intl/stringbundle;1"].
getService(Ci.nsIStringBundleService);
const strings =
sbs.createBundle("chrome://songbird/locale/songbird.properties");
const title = strings.GetStringFromName(
"prefs.main.downloads." + aContentType + ".chooseTitle");
const wm = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
const mainWin = wm.getMostRecentWindow("Songbird:Main");
// Need to prompt, launch the filepicker.
const folderPicker = Cc["@mozilla.org/filepicker;1"].
createInstance(Ci.nsIFilePicker);
folderPicker.init(mainWin, title, Ci.nsIFilePicker.modeGetFolder);
folderPicker.displayDirectory = downloadFolder;
if (folderPicker.show() != Ci.nsIFilePicker.returnOK) {
// This is our signal that the user cancelled the dialog. Some folks won't
// care, but most will.
throw new CE("User canceled the download dialog.", Cr.NS_ERROR_ABORT);
}
downloadFolder = folderPicker.file;
prefs.setValue(PREF_DOWNLOAD_FOLDER[aContentType], downloadFolder.path);
return downloadFolder;
}
sbDownloadDeviceHelper.prototype._checkAndRemoveExistingItem =
function sbDownloadDeviceHelper__checkAndRemoveExistingItem(aMediaItem)
{
var downloadMediaList = this.getDownloadMediaList();
if (downloadMediaList) {
var itemOriginUrl = aMediaItem.getProperty(SBProperties.originURL);
var listEnumerationListener = {
onEnumerationBegin: function() {
},
onEnumeratedItem: function(list, item) {
downloadMediaList.remove(item);
},
onEnumerationEnd: function() {
},
};
if ( (itemOriginUrl != "") &&
(itemOriginUrl != null) ) {
downloadMediaList.enumerateItemsByProperty(SBProperties.originURL,
itemOriginUrl,
listEnumerationListener);
}
}
}
sbDownloadDeviceHelper.prototype._getDownloadFolder_nothrow =
function sbDownloadDeviceHelper__getDownloadFolder_nothrow(aContentType)
{
// This function returns null if the user cancels the dialog.
try {
return this.getDownloadFolder(aContentType);
}
catch (e if e.result == Cr.NS_ERROR_ABORT) {
}
return null;
}
sbDownloadDeviceHelper.prototype._addItemToArrays =
function sbDownloadDeviceHelper__addItemToArrays(aMediaItem,
aURIArray,
aPropertyArrayArray)
{
aURIArray.appendElement(aMediaItem.contentSrc, false);
var dest = SBProperties.createArray();
var source = aMediaItem.getProperties();
for (let i = 0; i < source.length; i++) {
var prop = source.getPropertyAt(i);
// Filter our enableAutoDownload, as the Auto Downloader
// should ignore these items. Their download is already
// imminent:
if (prop.id != SBProperties.contentSrc &&
prop.id != SBProperties.enableAutoDownload)
{
dest.appendElement(prop, false);
}
}
var target = aMediaItem.library.guid + "," + aMediaItem.guid;
dest.appendProperty(SBProperties.downloadStatusTarget, target);
aPropertyArrayArray.appendElement(dest, false);
}
sbDownloadDeviceHelper.prototype._setDownloadDestinationIfNotSet =
function sbDownloadDeviceHelper__setDownloadDestinationIfNotSet(
aItems,
aMediaFileManagerOptions)
{
// Copy the Media File Manager options to an nsIPropertyBag
var bag = Cc["@mozilla.org/hash-property-bag;1"]
.createInstance(Ci.nsIWritablePropertyBag);
for (prop in aMediaFileManagerOptions) {
bag.setProperty(prop, aMediaFileManagerOptions[prop]);
}
// Use the Media File Manager to organize files into subfolders.
// The caller will designate the root folder for each media type
// in the MFM options bag (based on user preferences):
var mediaFileMgr = Cc["@songbirdnest.com/Songbird/media-manager/file;1"]
.createInstance(Ci.sbIMediaFileManager);
mediaFileMgr.init(bag);
for each (var item in aItems) {
try {
var curDestination = item.getProperty(SBProperties.destination);
if (!curDestination) {
let destFile = mediaFileMgr.getManagedPath(
item,
_MFM_GET_MANAGED_PATH_OPTIONS);
let path = destFile.path;
/// @todo Video items tend to have meaningless file names, because
/// they lack a trackName property. For now, strip off the leaf
/// name of unbetitled items, and
// sbDownloadSession::CompleteTransfer() will construct a
// file name from the source URL:
if (!item.getProperty(SBProperties.trackName)) {
// Leave a trailing delimiter so the path parses as a directory:
path = path.replace(/[^/\\]*$/, "");
}
// Ensure all paths are lowercase for Windows.
// See bug #7178.
let actualDestination = makeFileURL(path);
if(getPlatformString() == "Windows_NT") {
actualDestination = actualDestination.toLowerCase();
}
item.setProperty(SBProperties.destination, actualDestination);
}
}
catch (e) {
// We're not allowed to set the download destination on remote media items
// so that call may fail. The remoteAPI should unwrap all items and lists
// *before* handing them to us, so throw the error with a slightly more
// helpful message.
throw new CE("Download destination could not be set on this media item:\n"
+ " " + item + "\nIs it actually a remote media item?",
e.result);
}
}
}
function NSGetModule(compMgr, fileSpec) {
return XPCOMUtils.generateModule([sbDownloadDeviceHelper]);
}