Search code examples
javascriptfirebasegoogle-cloud-platformgoogle-cloud-functionsgoogle-cloud-storage

How can I refer formatted file name in cloud functions from client side JavaScript file?


I would like to make a web app using Firebase Hosting.

(I use Windows 10, Windows Subsystems for Linux, Debian 10.3 and Google Chrome browser. )

  1. make audio file using Cloud text to speech API
  2. upload that audio file to Cloud Storage
  3. play that audio file on a web browser

I use this code in step 1 and 2. This is in index.js (cloud functions)

var bucket = admin.storage().bucket('adva*******.appspot.com');
var dt = new Date();
var formatted = dt.toFormat('YYYYMMDDHH24MISS');
var file = bucket.file('audio/' + formatted + '.mp3');
// Create the file metadata
var metadata = {
    contentType: 'audio/mpeg'
};

// Performs the text-to-speech request
const [response] = await client.synthesizeSpeech(request);
return await file.save(response.audioContent, metadata)
.then(() => {
  console.log("File written to Firebase Storage.")
  return;

I use this code in step 3. This is in main.js (client side JavaScript file)

// Create a reference from a Google Cloud Storage URI
var storage = firebase.storage();
var pathReference = storage.ref('audio/audiofile.mp3')
pathReference.getDownloadURL().then(function(url) {
  // This can be downloaded directly:
  console.log(url);
  const audio = document.createElement('AUDIO');
  audio.controls = true;
  audio.src = url;
  const player = document.getElementById('player');
  player.appendChild(audio);
})

In main.js, I wrote audiofile.mp3, but it is bad because I named audio file usingvar formatted = dt.toFormat('YYYYMMDDHH24MISS');in index.js.

Therefore, my question is this. How can I write var pathReference = storage.ref(''audio/' + formatted + '.mp3'') in main.js?

Could you give me any advice? Thank you in advance.


my index.js (cloud functions)

const functions = require('firebase-functions');
var admin = require("firebase-admin");
admin.initializeApp();
const textToSpeech = require('@google-cloud/text-to-speech');
require('date-utils');

exports.myFunction = functions.firestore
  .document('messages/{id}')
  .onCreate((change, context) => {
        const client = new textToSpeech.TextToSpeechClient();
        async function quickStart() {

            // The text to synthesize
            const text = 'Hello world';

            // Construct the request
            const request = {
                input: {text: text},
                // Select the language and SSML voice gender (optional)
                voice: {languageCode: 'en-US', ssmlGender: 'NEUTRAL'},
                // select the type of audio encoding
                audioConfig: {audioEncoding: 'MP3'},
            };


            var bucket = admin.storage().bucket('adva*******.appspot.com');
            var dt = new Date();
            var formatted = dt.toFormat('YYYYMMDDHH24MISS');
            var file = bucket.file('audio/' + formatted + '.mp3');
            // Create the file metadata
            var metadata = {
                contentType: 'audio/mpeg'
            };

            // Performs the text-to-speech request
            const [response] = await client.synthesizeSpeech(request);
            return await file.save(response.audioContent, metadata)
            .then(() => {
              console.log("File written to Firebase Storage.")
              return;
            })
            .catch((error) => {
              console.error(error);
            });

        }
        quickStart();
    });

my main.js (client side)

'use strict';

// Saves a new message on the Cloud Firestore.
function saveMessage() {
  // Add a new message entry to the Firebase database.
  return firebase.firestore().collection('messages').add({
    text: messageInputElement.value,
    timestamp: firebase.firestore.FieldValue.serverTimestamp()
  }).catch(function(error) {
    console.error('Error writing new message to Firebase Database', error);
  });
}

// Checks that the Firebase SDK has been correctly setup and configured.
function checkSetup() {
  if (!window.firebase || !(firebase.app instanceof Function) || !firebase.app().options) {
    window.alert('You have not configured and imported the Firebase SDK. ' +
        'Make sure you go through the codelab setup instructions and make ' +
        'sure you are running the codelab using `firebase serve`');
  }
}

// Checks that Firebase has been imported.
checkSetup();

// Shortcuts to DOM Elements.
var messageInputElement = document.getElementById('text');
var submitButtonElement = document.getElementById('download');

// Saves message on form submit.
submitButtonElement.addEventListener('click', saveMessage);


// Create a reference from a Google Cloud Storage URI
var storage = firebase.storage();
var pathReference = storage.ref('audio/sub.mp3')
pathReference.getDownloadURL().then(function(url) {
  // This can be downloaded directly:
  console.log(url);
  const audio = document.createElement('AUDIO');
  audio.controls = true;
  audio.src = url;
  const player = document.getElementById('player');
  player.appendChild(audio);
}).catch(function(error) {
  // A full list of error codes is available at
  // https://firebase.google.com/docs/storage/web/handle-errors
  switch (error.code) {
    case 'storage/object-not-found':
      console.log('storage/object-not-found')
      break;

    case 'storage/unauthorized':
      console.log('storage/unauthorized')
      break;

    case 'storage/canceled':
      console.log('storage/canceled')
      break;

    case 'storage/unknown':
      console.log('storage/unknown')
      break;
  }  
});

my index.html

<!doctype html>
<html lang="ja">
   <head>
      <meta name="robots" content="noindex">

      <title>音読アプリ アドバンス</title>
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
      <link href="https://fonts.googleapis.com/css?family=M+PLUS+Rounded+1c&display=swap" rel="stylesheet">

      <style> 
            #text {width: 100%; height: 300px; font-family: 'M PLUS Rounded 1c', sans-serif; font-size: 22px;}

            #download {font-family: 'M PLUS Rounded 1c', sans-serif; font-size: 28px;}

      </style>
   </head>

   <body>
      <textarea id="text" class="form-control" name="text" placeholder="ここに英文を入力してください。" maxlength="3000" minlength="1"></textarea>
      <br>
      <div style="text-align:center">
        <input id="download" class="btn btn-primary" type="submit" value="音声をダウンロード">
      </div>
      <div id='player'></div>

      <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
      <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

      <!-- Import and configure the Firebase SDK -->
      <!-- These scripts are made available when the app is served or deployed on Firebase Hosting -->
      <!-- If you do not want to serve/host your project using Firebase Hosting see https://firebase.google.com/docs/web/setup -->
      <script src="/__/firebase/7.14.3/firebase-app.js"></script>
      <script src="/__/firebase/7.14.3/firebase-auth.js"></script>
      <script src="/__/firebase/7.14.3/firebase-storage.js"></script>
      <script src="/__/firebase/7.14.3/firebase-messaging.js"></script>
      <script src="/__/firebase/7.14.3/firebase-firestore.js"></script>
      <script src="/__/firebase/7.14.3/firebase-performance.js"></script>
      <script src="/__/firebase/7.14.3/firebase-functions.js"></script>
      <script src="/__/firebase/init.js"></script>

      <script src="scripts/main.js"></script>
   </body>
</html>

Solution

  • If I correctly understand your question (you need, in the front-end, to know the value of 'audio/' + formatted + '.mp3' that is set in the back-end, i.e. the in the Cloud Function), I think you could easily solve it with writing back to the message document that triggered the Cloud Function and, in your front-end, listen for changes to this document.

    Something along the following lines:

    Cloud Function

    exports.myFunction = functions.firestore
        .document('messages/{id}')
        .onCreate(async (snap) => {   // See the async here
    
            try {    //See the "global" try/catch
    
                const client = new textToSpeech.TextToSpeechClient();
    
                // The text to synthesize
                const text = 'Hello world';
    
                // Construct the request
                const request = {
                    input: { text: text },
                    // Select the language and SSML voice gender (optional)
                    voice: { languageCode: 'en-US', ssmlGender: 'NEUTRAL' },
                    // select the type of audio encoding
                    audioConfig: { audioEncoding: 'MP3' },
                };
    
    
                var bucket = admin.storage().bucket('adva*******.appspot.com');
                var dt = new Date();
                var formatted = dt.toFormat('YYYYMMDDHH24MISS');
                var file = bucket.file('audio/' + formatted + '.mp3');
                // Create the file metadata
                var metadata = {
                    contentType: 'audio/mpeg'
                };
    
                // Performs the text-to-speech request
                const [response] = await client.synthesizeSpeech(request);
                await file.save(response.audioContent, metadata);
                console.log("File written to Firebase Storage.");
    
                await snap.ref.update({ fileName: 'audio/' + formatted + '.mp3' });
    
                return null;
    
            } catch (error) {
                console.error(error);
            }
    
        });
    

    Front end

    function saveMessage() {
        // Add a new message entry to the Firebase database.
        firebase.firestore().collection('messages').add({
            text: messageInputElement.value,
            timestamp: firebase.firestore.FieldValue.serverTimestamp()
        })
            .then(docRef => {
    
                const firestoreDocListener = docRef.onSnapshot(doc => {
                    if (doc.exists && doc.data().hasOwnProperty('fileName')) {
                        console.log(doc.data().fileName);
                        // Use doc.data().fileName the way you need!
                    }
                });
    
            })
            .catch(function (error) {
                console.error('Error writing new message to Firebase Database', error);
            });
    }