Search code examples
javascriptvue.jsaxiosblobstrapi

Converting audio blob to file for upload to backend (without saving it locally)


EDIT: there were a couple of small typos/errors in here, which are corrected now and they solved half of the issues. The other half is in the accepted answer.

...

I am recording microphone-audio on the client side (nuxt/vue) and want to send it to my backend (Strapi). I have a MediaRecorder recorder and when the recording stops the data is being added to my recordingFile array. This part works, after recording I can play it back with the embedded player.

HTML part:

<audio
  id="localaudio"
  ..
></audio>

JS:

recorder = new MediaRecorder(mediaStream);

...     

recorder.addEventListener("dataavailable", function(e) { 
        document.querySelector("#localaudio").src = URL.createObjectURL(e.data); //add it to the player element on the page for playback
        recordingFile.push(e.data); // pushing to array recordingFile
      });

However, I am having troubles uploading it to my Strapi backend. I think the reason is I'm trying to upload a blob when Strapi expects a file.

  let blob = new Blob(recordingFile, { type: "audio/ogg" });

  const data = {
    "user" : "test",
    "files.File" : blob //prefix is strapi convention
  };

  const formData = new FormData();
  formData.append('data', JSON.stringify(data));

  axios({
    method: "post",
    url: "http://localhost:1337/recordings",
    data: formData,
    headers: {
      "content-type": `multipart/form-data;`
    }
  })

I do get a positive response and a new entry with user="test", but the file field stays empty. I tried sending the file-URL (URL.createObjectURL(..)) instead of the blob itself but it doesn't work either.

I am following instructions from strapi documentation but it uses files from the filesystem, not blobs created in the browser.

Any hints?

EDIT: recording.settings.json:

{
  "kind": "collectionType",
  "collectionName": "recordings",
  "info": {
    "name": "Recording"
  },
  "options": {
    "increments": true,
    "timestamps": true,
    "draftAndPublish": true
  },
  "attributes": {
    "File": {
      "model": "file",
      "via": "related",
      "allowedTypes": [
        "images",
        "files",
        "videos"
      ],
      "plugin": "upload",
      "required": false
    },
    "name": {
      "type": "string"
    }
  }
}

Solution

  • The documentation actually suggests that you append the file or blob (both should work) to the FormData instance instead of to the data object.

    let blob = new Blob(recordingFile, { type: "audio/ogg" });
    let file = new File([blob], 'recording.ogg');
    
    const data = {
      "user" : "test",
    };
    
    const formData = new FormData();
    formData.append('files.file', file);
    formData.append('data', JSON.stringify(data));