Search code examples
angularfirebase-storagehtml5-audioangularfire

How to download a file as a file


I'm trying to figure out how to download an audio file I've uploaded to firebase storage as a file. But all the various ways I've tried downloading the file, it just appears as an audio tag on another browser tab.

I've gathered that the Content-Disposition header is probably what I need to be dealing with, but I can't seem to find anything in the documentation or online in general about how to invoke the save file dialog of the browser when downloading the file.

I've used libraries like file-saver and I've tried URL.createObjectURL(blob) both they both behave the same way, which further makes me think that something needs to change on the firebase side.

Update

As requested, I'm sharing full code snippets of what I've tried.

Attempt with anchor tag

import { getBlob, ref, Storage } from '@angular/fire/storage';

async download(song: Song) {
    const fileName = song.url.split('/').reverse()[0];
    const storageRef = ref(this._storage, `songs/${fileName}`);
    const blob = await getBlob(storageRef);

    const blobURL = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = blobURL;
    a.download = fileName;
    a.click();
    URL.revokeObjectURL(blobURL);
}

Attenmpt with file-saver

import { saveAs } from 'file-saver';
import { getBlob, ref, Storage } from '@angular/fire/storage';

async download(song: Song) {
    const fileName = song.url.split('/').reverse()[0];
    const storageRef = ref(this._storage, `songs/${fileName}`);
    const blob = await getBlob(storageRef);

    saveAs(blob, fileName);
}

As you can see, I'm using a anchor tag with the download attribute set and the href attribute set and programmatically clicking the element. This still just opens a new tab and shows the audio player. So I tried a third-party library I've used in the past (file-saver) to see if they were able to solve this for me. However, this still has the same behavior as opening the file in a new window.

As I've alluded to above, my own research into this issue seems to be tied with the content disposition header. I'm not using the Angular HttpClient, as is obvious. So I was hoping if anyone knew how to acquire the file from Firebase Storage such that I can coerce the browser into giving me the file as a file and not as a player piece of media in a separate tab.


Solution

  • I genuinely don't know what happened between yesterday and today, but now saveAs from file-saver is doing what I want. I apologize this doesn't provide more insight, but if I venture to guess, I was making a silly mistake somewhere. I can't think of what's different from yesterday and today (I wasn't a good boy and didn't commit often). But the following is working for me:

      async download(song: Song) {
        const storageRef = ref(this._storage, `songs/${song.fileName}`);
        const blob = await getBlob(storageRef);
        saveAs(blob, song.fileName);
      }
    

    I'm no longer grabbing the file name from the url, and instead I'm saving the url and fileName on the doc, but that's the only difference I can find from what I was trying previously.