3
votes

So I have followed the Google's official sample for creating a Cloud Storage triggered Firebase Function that will create resized thumbnails from uploaded images and upload them to the Storage as well. Here it is simplified:

exports.generateThumbnail = functions.storage.object().onChange(event => {

    // get the uploaded file data (bucket, name, type...)

    // return if the file is not an image or name begins with "thumb_"

    // download the uploaded image in a temporary local file,
    // resize it using ImageMagick
    // upload it to storage with the name "thumb_<filename>"

}

However, when the new thumbnail uploads, the function gets triggered again and so forth in a loop. They have avoided that by returning if the uploaded file has a "thumb_" prefix.

You then end up with two images (the original and the thumbnail) and I want to rewrite the existing image with the thumbnail so I only have one image with the original path.

I don't know how to go about this because I don't know how to evade the reupload loop without a name change. I can delete the original image after uploading the thumbnail but the link pointing to the original image is already returned and saved in the Realtime Database (these images are profile pictures for users).

1
you only want the thumbnail image in storage?Bruno Ferreira
@BrunoFerreira yes, I want only the thumbnail, but I want it to have the path of the original image in the Storage, basically to overwrite the original datamj3c
you can try get the path of original image, upload the thumbnail to the path of original image and delete the original image for exemple if the original path is .../images you can create the thumbnail upload to the .../images path and delete the original image if you want to show with more contente I can create na answer.Bruno Ferreira
@BrunoFerreira I'm not sure we understand each other, this function is triggered just after the original image (let's say /avatars/zantsu.jpg) uploads, and this function creates a resized image and uploads the data to /avatars/thumb_zantsu.jpg, if I remove the prefix and upload the thumb to /avatars/zantsu.jpg, that will successfully overwrite the image but then the function triggers again and I don't know how to exit from it so it doesn't start reuploading it over againmj3c
you can get /avatars/zantsu.jpg create a thumbnail avatars/thumb_zantsu.jpg upload the thumbnail so /avatars/ path have two images thumb and original and when the thumbnail as uploaded sucessfully you delete the original /avatars/zantsu.jpg and the avatars/thumb_zantsu.jpg remains only the thumbnail, is it that i'm saingBruno Ferreira

1 Answers

12
votes

After looking at the bucket.js documentation in the @google-cloud/storage npm module, I have finally managed to overwrite the original file/path with the thumbnail image and also avoid the loop,

It can be done by attaching custom metadata when uploading the thumbnail, and testing for that metadata when the function triggers the next time.

I will just post the changes I made, the rest is the same as in the linked sample.

Here's the testing:

const filePath = event.data.name
const metadata = event.data.metadata

if (metadata.isThumb) {
    console.log('Exiting: Already a thumbnail')
    return
}

And here's the part when the spawn promise returns:

    return spawn(/* ... */)
}).then(_ => {
    console.log('Thumbnail created locally.')
    metadata.isThumb = true  // We add custom metadata
    const options = {
        destination: filePath,  // Destination is the same as original
        metadata: { metadata: metadata }
    }
    // We overwrite the (bigger) original image but keep the path
    return bucket.upload(/* localThumb */, options)
})