I need to take an audio recording and throw it to firebase, I do this, but the file type goes to firebase incorrectly, when it goes correctly, I cannot listen to the audio in firebase.
import {
useReactMediaRecorder,
} from "react-media-recorder";
const { status, startRecording, stopRecording, clearBlobUrl, mediaBlobUrl } =
useReactMediaRecorder({
audio: true,
blobPropertyBag: {
type: "audio/m4a",
},
});
const audioUpload = async (e: any) => {
saveMedia(reader.result?.toString(), user);
};
Firebase :
const uploadImage = async (
file: any,
user: IUser
): Promise<IUploadImage | null> => {
const storage = getStorage(firebaseApp);
const child = "1abcd/koray-test/" + idGenerator();
const imageRef = ref(storage, child);
const snapshot = await uploadToFirebase(imageRef, file);
if (!snapshot) {
return null;
}
const fbReference = snapshot.ref.fullPath;
return { fbReference, file };
};
Related
i'm using next js 13 with firebase v9. and i'm using a drop zone to upload images. the dropzone returns an array with blob as it's src.
[
{
id: 1
name: "image_processing20220628-4591-yzir35.png"
src: "blob:http://localhost:3000/6e2f33e5-a749-4e9a-b502-d20b8e3f38ca"
}
...
]
the above array is returned from the drop zone. and when i tried to upload to firebase storage it throws an error .
FirebaseError: Firebase Storage: Object 'livingImages/blob:http:/localhost:3000/ca0e3eaf-dbe9-4d77-8053-f4b6d1bd8600' does not exist. (storage/object-not-found)
so how can i upload blob of images to firebase storage?
const imgURL = [];
//this is the images stored inside Redux
const images = useSelector(selectImages);
const storage = getStorage();
images.map(async (file) => {
const storageRef = ref(storage, `livingImages/${file.src}`);
await getDownloadURL(storageRef).then((url) => {
imgURL.push(url);
});
});
const createDocument = () => {
const docRef = doc(db, "livingPosts", session?.user?.email);
const colRef = collection(docRef, "posts");
addDoc(colRef, {
name: "test upload",
images: imgURL,
});
};
the dropzone code
const dispatch = useDispatch();
const images = useSelector(selectImages);
const [files, setFiles] = useState(images == [] ? [] : images);
const {getRootProps, getInputProps} = useDropzone({
onDrop: (acceptedFiles) => {
acceptedFiles.map((file, index) => {
const reader = new FileReader();
reader.onload = async function (e) {
const options = {
maxSizeMB: 5,
maxWidthOrHeight: 1920,
useWebWorker: true,
};
const compressedFile = await imageCompression(file, options);
const tot = parseInt(acceptedFiles.length) + parseInt(files.length);
if (tot > 9) {
alert("select maximum of 9 images");
} else if (parseInt(acceptedFiles.length) > 9) {
alert("maximum images to be selected is 9");
} else if (parseInt(files.length) < 9) {
setFiles((prevState) => [
...prevState,
{
id: index,
src: URL.createObjectURL(compressedFile),
name: file.name,
},
]);
files.map((filename) => {
acceptedFiles.forEach((newFile) => {
if (newFile.name == filename.name) {
alert("a duplicate image is detected");
setFiles(
files,
files.filter((val) => val !== newFile)
);
}
});
});
} else {
alert("something went wrong");
}
};
reader.readAsDataURL(file);
return file;
});
},
})
and the output of the dropzone is
As mentioned in the comments, you'll need the actual File or Blob object to upload the file and not the object URL. You can set the blob in state as shown below:
setFiles((prevState) => [
...prevState,
{
id: index,
src: URL.createObjectURL(compressedFile),
blob: compressedFile, // <-- add blob
name: file.name,
},
]);
Then to upload the files and storing download URLs in Firestore document, try the following function:
import { ref, uploadBytes, getDownloadURL } from "firebase/storage";
import { addDoc } from "firebase/firestore";
const uploadFiles = async () => {
console.log(files);
const promises = files.map((file) => {
const storageRef = ref(storage, `images/${file.name}`);
return uploadBytes(storageRef, file.blob);
});
// upload all files
const res = await Promise.all(promises);
// get download URLs
const links = await Promise.all(res.map((r) => getDownloadURL(r.ref)));
console.log({ links })
// Add Firestore document
const colRef = collection(db, "livingPosts", session?.user?.email, "posts")
const docRef = await addDoc(colRef, {
name: "test",
images: links,
});
console.log("Document written with ID: ", docRef.id);
};
You can call this function on a submit button click or any event when you want to start the upload.
I'm trying to convert recordRTC webm file to mp4 using ffmpeg.js library in nextjs project, during conversion showing this issue
ffmpeg.FS('readFile', 'demo.mp4') error. Check if the path exists
const stopRecording = async () => {
if (recordRef.current) {
let blob = {}
recordRef.current.stopRecording(function(url) {
blob = recordRef.current.getBlob()
});
const webmFile = new File([blob], 'video.webm', {
type: 'video/webm'
})
convertBobToMpeg(webmFile)
}
}
const convertBobToMpeg = async (webmFile) => {
await ffmpeg.load();
await ffmpeg.FS('writeFile', 'video.webm', await fetchFile(webmFile))
ffmpeg.run('-i', 'video.webm', 'demo.mp4');
const data = await ffmpeg.FS('readFile', 'demo.mp4');
setVideo_obj(URL.createObjectURL(new Blob([data.buffer], {
type: 'video/mp4'
})))
}
I'm trying to adapt a React Native project to the new Firebase methods. In it I upload images to Storage and they are added to the App interface. I can also remove these images from the interface as shown in the following code:
const removeImage = (img) => { // delete an image selected by the user
Alert.alert(
"Eliminar imagen",
"¿Estás seguro de eliminar esta imagen?",
[
{
text: "Cancelar",
style: "cancel",
},
{
text: "Eliminar",
onPress: () => {
const result = filter(
formik.values.images,
(image) => image !== img
)
formik.setFieldValue("images", result)
},
},
],
{ cancelable: false }
)
}
The problem is that in this way, they are only removed from my App, while the images are still stored in Firebase. My idea is that when I remove the images from the frontend, they will also be removed from the Firebase Storage.
I have read Firebase documentation, and this would be possible with the deleteObject function
const storage = getStorage();
// Create a reference to the file to delete
const desertRef = ref(storage, 'images/desert.jpg');
// Delete the file
deleteObject(desertRef).then(() => {
// File deleted successfully
}).catch((error) => {
// Uh-oh, an error occurred!
})
I did some test, and I can't get it to work.
I don't know exactly how I should add the Firebase instructions shown here.
How should I implement this function in my code to remove images from Storage?
Thank you
import { getStorage, ref, deleteObject, uploadBytes, getDownloadURL } from "firebase/storage"
export function UploadImagesForm(props) {
const { formik } = props
const [isLoading, setIsLoading] = useState(false) // status for loading
// Function in charge of opening the image gallery
const openGallery = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
})
if (!result.cancelled) {
// console.log('buscando imagenes')
setIsLoading(true) // uploading the image
uploadImage(result.uri)
}
}
// function to upload the images to Firebase
const uploadImage = async (uri) => {
const response = await fetch(uri)
const blob = await response.blob()
const storage = getStorage()
const storageRef = ref(storage, `restaurants/${uuid()}`)
// we go to storage where we want to save the images
uploadBytes(storageRef, blob).then((snapshot) => {
// console.log(snapshot)
updatePhotosRestaurant(snapshot.metadata.fullPath)
})
}
// we take the URL in the previous function and set it in the state of the form
const updatePhotosRestaurant = async (imagePath) => {
const storage = getStorage()
const imageRef = ref(storage, imagePath)
const imageUrl = await getDownloadURL(imageRef) // get the url
// code to upload all images without replacing them
// get the current images and add the new ones with the array
formik.setFieldValue("images", [...formik.values.images, imageUrl])
setIsLoading(false)
}
const removeImage = (img) => { // delete an image selected by the user
Alert.alert(
"Eliminar imagen",
"¿Estás seguro de eliminar esta imagen?",
[
{
text: "Cancelar",
style: "cancel",
},
{
text: "Eliminar",
onPress: () => {
const result = filter(
formik.values.images,
(image) => image !== img
)
formik.setFieldValue("images", result)
},
},
],
{ cancelable: false }
)
}
return (
<>
<ScrollView
style={Styles.viewImage}
horizontal
showsHorizontalScrollIndicator={false}
>
<Icon
type="material-community"
name="camera"
color="#a7a7a7"
containerStyle={Styles.containerIcon}
onPress={openGallery}
/>
{map(formik.values.images, (image) => ( // display the images on the screen
<Avatar
key={image}
source={{ uri: image }}
containerStyle={Styles.imageStyle}
onPress={() => removeImage(image)}
/>
))}
</ScrollView>
<Text style={Styles.error}>{formik.errors.images}</Text>
<LoadingModal show={isLoading} text="Subiendo la imagen" />
</>
)
}
I finally figured out where to implement the deleteObject function in my file to make it all work.
You can delete the images from the Application and Firebase Storage at the same time.
I found a React expert who helped me with this.
As the Firebase documentation says:
To delete a file, first create a reference to that file.
( const imageRef = ref(storage, img ))
Firebase explains it like this:
import { getStorage, ref, deleteObject } from "firebase/storage";
const storage = getStorage();
// Create a reference to the file to delete
const desertRef = ref(storage, 'images/desert.jpg');
Then call the delete() method, (in my case: deleteObject(imageRef) ), for that reference, which will return either a Promise that resolves, or an error if the Promise is rejected.
import { getStorage, ref, deleteObject } from "firebase/storage";
const storage = getStorage();
// Create a reference to the file to delete
const desertRef = ref(storage, 'images/desert.jpg');
// Delete the file
deleteObject(desertRef).then(() => {
// File deleted successfully
}).catch((error) => {
// Uh-oh, an error occurred!
});
I just hope this can help other users who are in my situation learning Firebase
I show. the complete file so that they do not have the doubts that I had, which was the correct place where I should place the Firebase methods
const storage = getStorage()
const imageRef = ref(storage, img)
deleteObject(imageRef).then(() => { // also remove the image from Firebase
console.log("la imagen se elimino");
}).catch((error) => {
console.log("ocurrio un error: ", error)
})
Thanks to #FrankvanPuffelen and #BhavyaKoshiya who tried to help.
import { getStorage, ref, uploadBytes, getDownloadURL, deleteObject } from 'firebase/storage'
import { v4 as uuid } from 'uuid'
import { map, filter } from 'lodash'
import { LoadingModal } from '../../Shared/LoadingModal/LoadingModal'
import Styles from './Styles'
export function UploadImagesForm(props) {
const { formik } = props
const [isLoading, setIsLoading] = useState(false) // status for loading
// Function in charge of opening the image gallery
const openGallery = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
})
if (!result.cancelled) {
// console.log('buscando imagenes')
setIsLoading(true) // uploading the image
uploadImage(result.uri)
}
}
// function to upload the images to Firebase
const uploadImage = async (uri) => {
const response = await fetch(uri)
const blob = await response.blob()
const storage = getStorage()
const storageRef = ref(storage, `restaurants/${uuid()}`)
// we go to storage where we want to save the images
uploadBytes(storageRef, blob).then((snapshot) => {
// console.log(snapshot)
updatePhotosRestaurant(snapshot.metadata.fullPath)
})
}
// we take the URL in the previous function and set it in the state of the form
const updatePhotosRestaurant = async (imagePath) => {
const storage = getStorage()
const imageRef = ref(storage, imagePath)
const imageUrl = await getDownloadURL(imageRef) // get the url
// code to upload all images without replacing them
// get the current images and add the new ones with the array
formik.setFieldValue("images", [...formik.values.images, imageUrl])
setIsLoading(false)
}
const removeImage = (img) => { // delete an image selected by the user
Alert.alert(
"Eliminar imagen",
"¿Estás seguro de eliminar esta imagen?",
[
{
text: "Cancelar",
style: "cancel",
},
{
text: "Eliminar",
onPress: async () => {
const result = filter(
formik.values.images,
(image) => image !== img
)
formik.setFieldValue("images", result)
**// THIS IS THE CODE I ADDED FROM FIREBASE**
const storage = getStorage()
const imageRef = ref(storage, img)
deleteObject(imageRef).then(() => { // also remove the image from Firebase
console.log("la imagen se elimino");
}).catch((error) => {
console.log("ocurrio un error: ", error)
})
**// END OF THE CODE I ADDED FROM FIREBASE**
},
},
],
{ cancelable: false }
)
}
Great explanation! If anyone has the ref URLs stored in state already, I added the below to my useImages hook and it worked great.
const storage = getStorage();
const deleteImg = (refUrl) => {
const imageRef = ref(storage, refUrl)
deleteObject(imageRef)
.catch((error) => {
console.log("Failed to delete image: ", error)
})
}
You can try this
let imageRef = storage.refFromURL(URL);
imageRef.delete()
I'm following this tutorial https://www.apollographql.com/docs/tutorial/mutation-resolvers/#book-trips
and have ended up getting this error:
"TypeError: Cannot read property 'findOrCreateUser' of undefined",
" at login
Below is the function I use to call login:
mutation LoginUser {
login(email: "daisy#apollographql.com") {
token
}
}
The file below is where findOrCreateUser is called:
src/resolvers.js
module.exports = {
Mutation: {
login: async (_, {email}, {dataSources}) => {
const user = await dataSources.userAPI.findOrCreateUser({ email });
if (user) {
user.token = Buffer.from(email).toString('base64');
return user;
}
},
},
This is where dataSources is defined:
src/index.js
require('dotenv').config();
const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const { createStore } = require('./utils');
const resolvers = require('./resolvers');
const isEmail = require('isemail');
const LaunchAPI = require('./datasources/launch');
const UserAPI = require('./datasources/user');
const store = createStore();
const server = new ApolloServer({
context: async ({req}) => {
const auth = req.headers && req.headers.authorization || '';
const email = Buffer.from(auth, 'base64').toString('ascii');
if (!isEmail.validate(email)) return {user: null};
// find a user by their email
const users = await store.user.findOrCreate({ where: { email } });
const user = users && users[0] || null;
return { user: {...user.dataValues } };
},
dataSources: () => ({
launchAPI: new LaunchAPI(),
UserAPI: new UserAPI({store})
}),
typeDefs,
resolvers,
});
server.listen().then(() => {
console.log(`
Server is running!
Listening on port 4000
Explore at https://studio.apollographql.com/dev
`)
});
As xadm mentioned in the comment the issues is your usage of userAPI vs UserAPI. the datasource object is created in index.js in the following block
dataSources: () => ({
launchAPI: new LaunchAPI(),
UserAPI: new UserAPI({store})
}),
here you defined datasources.UserAPI however in resolvers.js you refer to it as datasources.userAPI (note the difference in capitalization of userAPI). Your problem can be resolved by changing the above code block to
dataSources: () => ({
launchAPI: new LaunchAPI(),
userAPI: new UserAPI({store})
}),
I am trying to create a video chat with twilio. I could turn the webcam and run the video, however i could not make the audio work. When i select the control, i get to enlarge the video and picture to picture mode but not control the audio.
This is how seen
Here is the code
function App() {
let localMediaRef = React.useRef(null);;
const [data, setIdentity] = React.useState({
identity: null,
token: null
});
const [room, setRoom] = React.useState({
activeRoom: null,
localMediaAvailable: null,
hasJoinedRoom: null
});
async function fetchToken() {
try {
const response = await fetch("/token");
const jsonResponse = await response.json();
const { identity, token } = jsonResponse;
setIdentity({
identity,
token
});
} catch (e) {
console.error("e", e);
}
}
React.useEffect(() => {
fetchToken();
}, []);
const attachTracks = (tracks, container) => {
tracks.forEach(track => {
container.appendChild(track.attach());
});
};
// Attaches a track to a specified DOM container
const attachParticipantTracks = (participant, container) => {
const tracks = Array.from(participant.tracks.values());
attachTracks(tracks, container);
};
const roomJoined = room => {
// Called when a participant joins a room
console.log("Joined as '" + data.identity + "'");
setRoom({
activeRoom: room,
localMediaAvailable: true,
hasJoinedRoom: true
});
// Attach LocalParticipant's Tracks, if not already attached.
const previewContainer = localMediaRef.current;
if (!previewContainer.querySelector("video")) {
attachParticipantTracks(room.localParticipant, previewContainer);
}
};
const joinRoom = () => {
let connectOptions = {
name: "Interview Testing"
};
let settings = {
audio: true
}
console.log('data', data, data.token)
Video.connect(
data.token,
connectOptions,
settings
).then(roomJoined, error => {
alert("Could not connect to Twilio: " + error.message);
});
};
return (
<div className="App">
<FeatureGrid>
<span onClick={joinRoom}>Webcam</span>
</FeatureGrid>
<PanelGrid>
{room.localMediaAvailable ? (
<VideoPanels>
<VideoPanel ref={localMediaRef} />
</VideoPanels>
) : (
""
)}
</PanelGrid>
</div>
);
}
export default App;
How do i enable audio too? Also the settings of video is shown only after right click. can't we show this by default?
UPDATE
its a LocalAudioTrack
this is remoteaudiotrack