Search code examples
cordovaangularionic2file-transferangular2-http

Download files with angular2 - ionic 2


I have an Ionic 2 app, and I need to download audios from soundcloud. I already have the url that I need to do the request:

let url = `https://api.soundcloud.com/tracks/${audio.id}/download?client_id=${this.SC_CLIENT_ID}`

I want to know how to do this. I tryed with FileTransfer:

public download(audio: any): void {

        this.platform.ready().then(() => {
            console.log("Clickeo para descargar: " + audio.id);

            let url = `https://api.soundcloud.com/tracks/${audio.id}/download?client_id=${this.SC_CLIENT_ID}`;

            let pathToSaveTo: string = '';

            if (this.platform.is('android')) {
                pathToSaveTo = cordova.file.externalApplicationStorageDirectory + audio.id + '.wav';

                let fileTransfer = new Transfer();

                fileTransfer.onProgress(this.onProgress);

                fileTransfer.download(url, pathToSaveTo)
                    .then((entry) => {
                        console.log('download complete: ' + entry.toURL());
                    }, (error) => {

                        let prompt = this.alertCtrl.create({
                            title: 'Error',
                            subTitle: error,
                            buttons: ['Accept']
                        });

                        prompt.present();
                    });
            }
        });

    }

    onProgress = (progressEvent: ProgressEvent) : void => {
        this.ngZone.run(() => {
            if (progressEvent.lengthComputable) {
                let progress: any = Math.round((progressEvent.loaded / progressEvent.total) * 100);
                console.log(progress);
                let toast = this.toastCtrl.create({
                  message: progress,
                  duration: 100
                });
                toast.present();
            }
        });
    }

But it always download a zero KB file. Any solution? Maybe angular2 way, or I'm doing it wrong? If I put this url in browser, with the properly audio id and mi client id, it starts to download, but not with FileTransfer.

Thank's so much in advance.

Ivan.


Solution

  • My problem was that soundcloud returned a response with redirect. I had to detect the redirect state and manually redirect to the response.headers.Location

    That is the working code:

    public download(localAudio: LocalAudio): void {
        let fileName: string = localAudio.id + '.mp3';
    
        var audio: StorageAudio = {
            localAudio: localAudio,
            url: `https://api.soundcloud.com/tracks/${localAudio.id}/download?client_id=${this.SC_CLIENT_ID}`,
            fileName: fileName,
            filePath: this.file.dataDirectory + fileName
        };
    
        if (this.platform.is('ios')) {
            audio.filePath = audio.filePath.replace(/^file:\/\//, '');
        }
    
        this.toastNotifications.showStartingDownloadMsg();
    
        this.http.downloadFile(audio.url, {}, {}, audio.filePath).then(response => {
            this.toastNotifications.showDownloadCompleteMsg();
    
            this.storeAudioInformation(audio);
        }).catch(response => {
            /**
             * Handle redirects if exist.
             */
            if (this.hasRedirection(response)) {
                console.log("Redirect to " + response.headers.Location);
                audio.url = response.headers.Location;
    
                this.redirectToDownload(audio);
            } else {
                this.toastNotifications.showDownloadErrorMsg();
            }
        });
    }
    
    public hasRedirection(response: any): boolean {
        return (response.headers.Location && (response.status === 301 || response.status === 302));
    }
    
    public redirectToDownload(audio: StorageAudio): void {
        this.http.downloadFile(audio.url, {}, {}, audio.filePath).then(response => {
            this.toastNotifications.showDownloadCompleteMsg();
    
            this.storeAudioInformation(audio);
        }).catch(response => {
            console.log("Error catch: " + JSON.stringify(response));
        });
    }