How to upload audio file to Firebase Storage? - angularjs

I'm trying to upload audio file to Firebase Storage in my Ionic2 project.
First I recorded a audio file using Media plugin (Cordova plugin), and this file is playing well. From the Android storage and from the media plugin method (this.media.play()...;).
Second I need to push the recorded file to Firebase Storage.
this is my code:
let storageRef = firebase.storage().ref();
let metadata = {
contentType: 'audio/mp3',
};
let filePath = `${this.file.externalDataDirectory}`+`${this.fileName}`;
const voiceRef = storageRef.child(`voices/${this.fileName}`);
var blob = new Blob([filePath], {type: 'audio/mp3'});
voiceRef.put(blob);
After reading the Firebase doc, I can push blob to Firebase.
The file is successfully pushed to Firebase Storage with empty data (95 Byte).
this is screenshot:

The problem isn't a Firebase issue
My problem is solved by using the File cordova plugin method (readAsDataURL()) and the putString(fileBase64,firebase.storage.StringFormat.DATA_URL) method.
First, I create a file reference:
let filePath = "this.file.externalDataDirectory" + "this.fileName";
Then I transform the file to a base64 string by using the readAsDataURL method that returns a promise containing the file as a string base64. Also, I push the file to Firebase using the putString method that has two parameters the File that returned by the readAsDataURL and the second is firebase.storage.StringFormat.DATA_URL.
My Final code:
let storageRef = firebase.storage().ref();
let metadata = {
contentType: 'audio/mp3',
};
let filePath = `${this.file.externalDataDirectory}` + `${this.fileName}`;
this.file.readAsDataURL(this.file.externalDataDirectory, this.fileName).then((file) => {
let voiceRef = storageRef.child(`voices/${this.fileName}`).putString(file, firebase.storage.StringFormat.DATA_URL);
voiceRef.on(firebase.storage.TaskEvent.STATE_CHANGED, (snapshot) => {
console.log("uploading");
}, (e) => {
reject(e);
console.log(JSON.stringify(e, null, 2));
}, () => {
var downloadURL = voiceRef.snapshot.downloadURL;
resolve(downloadURL);
});
});
That's working fine for me.
Thanks.

Related

Firebase Storage not displaying image properly (shows a small box)

EDIT: I've updated the CORS config but its still showing the same error.
I have a Tinymce RTE on my page, and when u drop an image into the editor, I have some functions that upload it to firebase storage, then swaps out the src of the text editor with the url fetched from firebase. It works kinda ok, but its being displayed as a broken link image icon.
When I check the link, its because originally it downloads the image when the link is clicked. I added a metadata property when it uploads it, but now its just showing a tiny box.
Here is the code where the image dropped into the editor is uploaded into firebase storage
const imagesUploadHandler = async (blobInfo, success, failure) => {
try {
const file = blobInfo.blob();
const storageRef = ref(storage, file.name);
const metadata = {
contentType: 'image/jpeg',
};
await uploadBytes(storageRef, file, metadata);
const url = await getDownloadURL(storageRef);
console.log(url);
return url;
} catch (error) {
// Call the failure callback with the error message
console.log(error.message);
}
};
Originally, i didnt include the contentType metadata, and it was just uploading as application/octet-stream, which i assume is why it prompts you to save the image.
Image link: https://firebasestorage.googleapis.com/v0/b/cloudnoise-news.appspot.com/o/ref.jpg?alt=media&token=1edc90e7-1668-4a06-92a3-965ce275798b
Currently its displaying this
Somethings i checked through
firebase storage rules is in test mode, so should be able to read and write by anyone.
i tried sticking in different MIME types but it either shows the tiny box, or it shows "undefined"
the files upload successfully and the "swap" in Tinymce editor is also all good.
Any idea why this is happening?
you need to set the metadata tag
const metadata = {
contentType: file.type,
};
This should ensure that the correct content type is set when the image is uploaded to Firebase Storage.
If this does not resolve the issue, you may need to check that the URL returned from getDownloadURL is valid and points to the correct image. You can try opening the URL in a new browser tab to verify that the image is accessible.
I fixed it by adding a blob, I created a blob object with the file data, then i just made it upload the blob object instead of the single file.
const imagesUploadHandler = async (blobInfo, success, failure) => {
try {
const file = blobInfo.blob();
const storageRef = ref(storage, file.name);
const metadata = {
contentType: file.type,
};
// Create a new Blob object with the file data
const blob2 = await new Blob([file], { type: file.type });
// Upload the Blob to Firebase Storage
await uploadBytes(storageRef, blob2, metadata);
const url = await getDownloadURL(storageRef);
console.log(url);
return url;
} catch (error) {
// Call the failure callback with the error message;;
console.log(error.message)
}
};

Firebase Storage, JSPDF Not Keeping Images

I am building a PDF in JSPDF with react. I am adding an image to this pdf using takescreenshot() from ArcGIS API (it is an image of a map). After creating the PDF I can download it no problem, but if I upload the PDF to firebase storage and automate an email with the downloadURL from firebase storage, the PDF no longer has the image in it.
I'm assuming there is some issue with firebase incorporating the image due to CORS, but I'm curious if anyone else has run into something like this.
Here is my code:
var blob = pdf.output('blob');
var id = uuid();
var storageRef = firebase.storage().ref(`${userInfo.currentCompany}`);
var storageRefName = `${moment().format('YYYY-MM-DD')}_${userInfo.currentAccount}.pdf`;
var noSpaceRef = storageRefName.replace(/\s/g, '_');
var uploadTask = storageRef.child(noSpaceRef).put(blob);
uploadTask.on('state_changed', (snapshot) =>
{
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(progress);
}, function (error)
{
console.log(error);
}, () =>
{
uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) =>
{
this.sendEmail(downloadURL)
});
});
Any help is appreciated!
When in doubt, make sure you're still passing the correct props. My blob was technically different when I would hit my download PDF button compared to email PDF button.
Classic.

upload image to S3 presigned url using react-native-image-picker and axios

I am trying to get an presigned url image upload working correctly. Currently the upload succeeds when selecting an image from the IOS simulator, however when I actually try to view the file it seems the file is corrupted and will not open as an image. I suspect it has something to do with my FormData but not sure.
export async function receiptUpload(file) {
const date = new Date();
const headers = await getAWSHeaders();
const presignUrl = await request.post(
urls.fileUpload.presignUpload,
{file_name: `${date.getTime()}.jpg`},
{headers}
)
.then(res => res.data);
const formData = new FormData();
formData.append('file', {
name: `${date.getTime()}.jpg`,
uri: file.uri,
type: file.type
});
const fileUpload = presignUrl.presignUrl && await request.put(
presignUrl.presignUrl,
formData
)
.then(res => res.status === 200);
}
I have tried from other fixes to change the file uri like so...
Platform.OS === 'android' ? file.uri : file.uri.replace('file://', '');
however this does not seem to work either.
I did this just recently in my current project and the following code is a working example for my use case. I didn't need to convert to a blob either though I am uploading to AWS S3 so if you are uploading elsewhere that may be the issue.
export const uploadMedia = async (fileData, s3Data, setUploadProgress = () => {}) => {
let sendData = { ...fileData };
sendData.data.type = sendData.type;
let formData = new FormData();
formData.append('key', s3Data.s3Key);
formData.append('Content-Type', fileData.type);
formData.append('AWSAccessKeyId', s3Data.awsAccessKey);
formData.append('acl', 'public-read');
formData.append('policy', s3Data.s3Policy);
formData.append('signature', s3Data.s3Signature);
formData.append('file', sendData.data);
return axios({
method: 'POST',
url: `https://${s3Data.s3Bucket}.s3.amazonaws.com/`,
data: formData,
onUploadProgress: progressEvent => {
let percentCompleted = Math.floor((progressEvent.loaded * 100) / progressEvent.total)
setUploadProgress(percentCompleted);
}
})
}
I would first check to see where the issue is occurring. After uploading can you view it on whatever storage service you are trying to upload it to. If so it's something on React Native side. If it doesn't ever get uploaded to the location you know its an error in your upload process. Might help you track the exact location of the error.
I had to do this recently for a project. I believe the data is a base64 string when coming directly from the file input. So the issue is your are uploading a base64 string not the image by simply passing the data field. I had to process it before uploading to the signed URL with the following method.
private dataUriToBlob(dataUri) {
const binary = atob(dataUri.split(',')[1]);
const array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], { type: 'image/jpeg' });
}
This answer fixed it for me: How can I upload image directly on Amazon S3 in React Native?
I had tried uploading with axios and fetch with FormData. The download went through but the image file was not readable, even when downloaded to my Mac from the S3 console:
The file "yourfile.jpg" could not be opened. It may be damaged or use a file format that Preview doesn’t recognize.
Only after trying to upload with XHR with the correct Content-Type header did it work. Your signedUrl should be correct as well, which seems to be the case if the download goes through.

Photo uploaded to firebase does not open correctly

In storage it creates a hierarchy of folders, the same is in the path of the image, inside these folders it creates the image file, but when I download this image it does not open.
const finalizarAlbum = () => {
let albumNumber = Date.now();
let username = email.split('#')[0] + '_' + albumNumber;
let pathImage =
'file:///data/user/0/com.master/cache/tm-rn-image-crop-picker/8f403c24-c538-43f4-bb8d-e6c83be46a36.jpg';
firebase
.storage()
.ref()
.child('imagens')
.putString(pathImage)
.on(
'state_changed',
snapshot => {
let pct = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
},
error => {
alert(error.code);
},
() => {}
);
};
Since your code calls putString() it is writing the string "file:///data/user/0/com.master/cache/tm-rn-image-crop-picker/8f403c24-c538-43f4-bb8d-e6c83be46a36.jpg" to Cloud Storage, not the contents of the file that the string refers to.
To upload the actual contents of the file, you'll want to call the putFile() method (if you're using react-native-firebase, or the put method with a File or Blob reference (if you're using the regular JavaScript SDK.

Upload to Firebase Storage executes but image comes back as a black square. Tried everything

Hey I've been building out a full-stack tinder app using react native + firebase auth/storage/realtimedb.
Everything has been going great so far but I've ran into an issue a few days ago and I don't know what's wrong with it.
I get back the correct uri of the image and pass it in as parameters to my uploadImage function and convert that to a blob. It uploads a file to firebase storage but it's not my image. This is what gets uploaded:
Image that is getting uploaded.
Weird things going on in the file description of my 'image'
The first things I notice is when I upload the image and look at the description of the supposed image I see that the size is 600,000 bytes which is strange because when I upload the pictures manually through the firebase storage console they are a few megabytes.
The second thing is the image preview is not working.
editAvi = async () => {
console.log('wtf')
await Permissions.askAsync(Permissions.CAMERA_ROLL);
const { cancelled, uri } = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
});
if (!cancelled) {
this.setState({ image: uri });
}
console.log('The image is' + this.state.image)
};
uploadImage = async (uri, imageName) => {
// Create file metadata including the content type
var metadata = {
contentType: 'image/jpeg',
}
// Points to the root reference
var storageRef = firebase.storage().ref();
// Points to 'images'
const response = await fetch(uri);
const blob = await response.blob();
var ref = storageRef.child('images/' + this.state.currentID);
ref.put(uri, metadata);
console.log('This is the blob: ' + blob)
}
I've been researching this extensively for two days and have asked about it multiple times in a web development discord I'm in and I still can't fix it.
Please help me fix this! This is one of the last things I need to get this app done. :)
Found this question when I was also searching for an answer. I was able to solve this following the recommendation from a Github issue https://github.com/expo/expo/issues/2402#issuecomment-443726662
The main idea is to replace
const response = await fetch(uri);
const blob = await response.blob();
var ref = storageRef.child('images/' + this.state.currentID);
ref.put(uri, metadata);
with
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = () => {
resolve(xhr.response);
};
xhr.onerror = (e) => {
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", uri, true);
xhr.send(null);
});
var ref = storageRef.child('images/' + this.state.currentID);
ref.put(blob, metadata);
Fetch in know to have a problem in ReacNative when using Expo.
Hope this solves it.
Found this question when I was searching around for a solution to the exact same issue. I fixed it after about 12 hours of trial and error by adding 'application/octet-stream;BASE64' a the type when creating the blob (using rn-fetch-blob).
Blob.build(data, { type: 'application/octet-stream;BASE64' });
Not sure if that's the method you're using to create the blob, but if so, using that as the type fixed the issue for me.

Resources