Why doesn't Microsoft Skydrive download multiple files even though MS example shows it? (wl.download)

668 views Asked by At

Summary

I am attempting to find out why the wl.download function will not download more than one file even though the Microsoft examples seem to indicate that they can. And, the code seems to be called for each file you attempt to download, but only the one file is actually downloaded.

Details Here are the details of how you can see this problem which I've tried in IE 11.x and Chrome 30.x

If you will kindly go to : http://isdk.dev.live.com/dev/isdk/ISDK.aspx?category=scenarioGroup_skyDrive&index=0

You will be able to run an example app which allows you to download files from your skydrive.

Note: the app does require you to allow the app to access your skydrive.

Once you get there you'll see code that looks like this on the right side of the page: enter image description here

Alter One Value: select:

You need to alter one value: Change the

select: 'single' to

select: 'multi' 

which will allow you to select numerous files to download to your computer. If you do not make that one change then you won't be able to choose more than one file in the File dialog.

Click the Run Button to Start

Next, you'll see a [Run] button to start the app (above the code sample). Go ahead and click that button.

Pick Files For Download

After that just traverse through your skydrive files and choose more than one in a folder and click the [Open] button. At that point, you will see one of the files actually downloads, and a number of file names are displayed in the bottom (output) section of the example web page.

My Questions

  1. Why is it that the others do not download, even though wl.download is called in the loop, just as the console.log is called in the loop?

  2. Is this a known limitation of the browser?

  3. Is this a known bug in skydrive API?
  4. Is this just a bug in the example code?
2

There are 2 answers

1
nick_w On BEST ANSWER

The problem here is that the call to wl.download({ "path": file.id + "/content" }) stores some internal state (among other things, the file being downloaded and the current status thereof). By looping over the list of files, that state is in fact overwritten with each call. When I tried downloading three text files at once, it was always the last one that was actually downloaded and never the first two.

The difficulty here is that the downloads are executed in the traditional fashion, whereby the server adds Content-Disposition: attachment to the response headers to force the browser to download the file. Because of this, it is not possible to receive notification of any kind when the download has actually completed, meaning that you can't perform the downloads serially to get around the state problem.

One approach that I thought might work is inspired by this question. According to the documentation, we can get a download link to a file if we append /content?suppress_redirects=true to its id. Using this approach, we can set the src property of an IFrame and download the file that way. This works OK, but it will only force a download for file types that the browser can't natively display (zip files, Exe files, etc.) due to the lack of the Content-Disposition: attachment response header.

The following is what I used in the Interactive Live SDK.

WL.init({ client_id: clientId, redirect_uri: redirectUri });

WL.login({ "scope": "wl.skydrive wl.signin" }).then(
    function(response) {
        openFromSkyDrive();
    },
    function(response) {
        log("Failed to authenticate.");
    }
);

function openFromSkyDrive() {
    WL.fileDialog({
        mode: 'open',
        select: 'multi'
    }).then(
        function(response) {
            log("The following file is being downloaded:");
            log("");

            var files = response.data.files;
            for (var i = 0; i < files.length; i++) {
                var file = files[i];
                log(file.name);

                WL.api({
                    path: file.id + "/content?suppress_redirects=true",
                    method: "GET"
                }).then(
                    function (response) {                    
                        var iframe = document.createElement("iframe"); 
                        iframe.src = response.location;             
                        iframe.style.display = "none";
                        document.body.appendChild(iframe); 
                    },
                    function (responseFailed) {
                        log("Error calling API: " + responseFailed.error.message);
                    } 
                );

            }
        },
        function(errorResponse) {
            log("WL.fileDialog errorResponse = " + JSON.stringify(errorResponse));
        }
    );
}

function log(message) {
    var child = document.createTextNode(message);
    var parent = document.getElementById('JsOutputDiv') || document.body;
    parent.appendChild(child);
    parent.appendChild(document.createElement("br"));
}
1
Stijn van Grinsven On

Did you try to bind some events to the WL.download() method? According to the documentation:

The WL.download method accepts only one parameter: The required path parameter specifies the unique SkyDrive file ID of the file to download. If the WL.download method call is unsuccessful, you can use its then method's onError parameter to report the error. In this case, the WL.download doesn't support the onSuccess and onProgress parameters. If the WL.download method call is successful, the user experience for actually downloading the files will differ based on the type of web browser in use.

Perhaps you are getting some errors in your log to identify the problem.

For me, one suggestion without having checked the documentation, I can think of the fact that you are not waiting for each download to end. Why not change your loop in such a manner that you call WL.download() only if you know no other download is currently running ( like calling the next WL.download only in the success/complete event ):

WL.download({ "path": file.id + "/content" }).then(
    function (response) {
        window.console && console.log("File downloaded."); 
        //call the next WL.download() here <!-----------------
    },
    function (responseFailed) {
        window.console && console.log( "Error downloading file: " + responseFailed.error.message); 

    }
);