How to get the resized downloadUrl after upload with firebase storage (Web SDK + Resize images extention)
Asked Answered
R

1

13

With the Firebase Web SDK, I can easily get the downloadUrl after upload a file

const task = firebase.ref().child('myFolder').put(file, metadata)
task.then(snapshot => {
 snapshot.ref.getDownloadURL()) 
}

But I installed the Resize Images Extention and now, I want to get the resized downloadUrl as soon as it is available. How to do that ? I do not find any explanations about it...

Rounce answered 21/11, 2019 at 14:27 Comment(0)
L
14

The extension deterministicly determines the new file name based on how you configured it. You can see the exact code for how the name is determined in the extension's source code.

When you installed the extension, it asked for a path to the resized images which is relative to the path of the original. That is the path to the new image (relative, of course, to the original).

Beyond that, the documentation states that it will be suffixed with the configured width and height.

Names the resized image using the same name as the original uploaded image, but suffixed with your specified width and height.

So, if you didn't specify a path, and you specified 200x200, and then uploaded image.jpg to root of the bucket, the new name would be: image_200x200.jpg, at the root of the bucket.

If you specified the path resized, and you specified 200x200, and the uploaded image2.jpg to the root of the bucket, the new name would be /resized/image2_200x200.jpg in the same bucket as the source image.

To get the download URL, you will need to call getDownloadURL on a storage reference with the new name once the extension function has created the new file.

If you want to wait, you can poll with code similar to the following:

function delay(t, v) {
  return new Promise(function(resolve) { 
    setTimeout(resolve.bind(null, v), t)
  });
}

function keepTrying(triesRemaining, storageRef) {
  if (triesRemaining < 0) {
    return Promise.reject('out of tries');
  }

  return storageRef.getDownloadURL().then((url) => {
    return url;
  }).catch((error) => {
    switch (error.code) {
      case 'storage/object-not-found':
        return delay(2000).then(() => {
          return keepTrying(triesRemaining - 1, storageRef)
        });
      default:
        console.log(error);
        return Promise.reject(error);
    }
  })
}

And this is how you would call it after the upload:

const storageRef = firebase.storage().ref().child('image_200x200.jpg');
keepTrying(10, storageRef).then((url) => console.log(url));
Lisalisabet answered 21/11, 2019 at 15:8 Comment(5)
Probably not the only way -- e.g. another cloud function could look for the file created by the extension (e.g. by triggering on the destination path) and then trigger an update to RTDB or Firestore, or send a cloud message, or something, I suppose. This seemed most straightforward.Lisalisabet
And the best practice is to store the downloadUrl or the reference in my database ?Rounce
It seems more natural to me to store the pathname or gs:// url than to store the download url, since its more flexible to do other operations on.Lisalisabet
Awesome thanks. Not sure what your delay function was doing but I replaced it with this: delay(t) { return new Promise(resolve => { setTimeout(resolve, t); }); } Also if you are using AngularFire it returns an observable so you have to convert it to a promise ".getDownloadURL().toPromise().then".Extractive
Another way would be to put a firebase trigger on the storage and then when a file is created write it to a firestore collection. You could watch this collection to see when new files appear and then check the expected file name. A lot more work than this solution though.Extractive

© 2022 - 2024 — McMap. All rights reserved.