I'm trying to make a simple web page just to play around with Firebase. I'm currently working on users uploading their photos and storing them as well as a reference to them in the database. I had a working version except the only issue was that if multiple users opened the page at the same time, only the most recent post would last. I wanted to use the realtime function to overcome this and have come up with this.
var postRef = firebase.database().ref('variables/postNumber');
postRef.on('value',function(snapshot) {
var postName = snapshot.val();
var uploader = document.getElementById('uploader');
var filebutton = document.getElementById('filebutton');
// get file
filebutton.addEventListener('change', function(e) {
var file = e.target.files[0];
var ext = file.name.split('.').pop();;
console.log(postName);
console.log(ext);
//create a storage ref
var storageRef = firebase.storage().ref('posts/' + postName + "." + ext);
var task = storageRef.put(file);
publishPost(postName, ext);
function publishPost(postName, ext) {
firebase.database().ref('posts/' + postName).set({
postID: postName,
postDate: Date(),
fileType : ext
});
firebase.database().ref('variables/').set({
postNumber: postName + 1
});
}
task.on('state_changed',
function progress(snapshot){
var percentage = (snapshot.bytesTransferred / snapshot.totalBytes) *100;
uploader.value = percentage;
},
function error(err){
},
function complete(postName, ext){
uploader.value = 0;
window.alert('Your meme Uploaded correctly');
},
);
});
});
This works well, always updating the postName variable except when a new user posts, it will rewrite every post to the new post. For example, if user A posts a picture while user B was already on the page, then when user B posts, his post will upload twice the first time overriding user A's post. Can anyone shed some light on why this is happening? I was thinking of moving the listener to start the function but not sure if thats the right choice.
What happens is that the event listener is attached to the button every time new value is detected. Which means that the change event listener on filebutton cannot be in the observer at all.
Working code:
let postName = null;
var postRef = firebase.database().ref('variables/postNumber');
postRef.on('value', function(snapshot) {
const value = snapshot.val();
if (value === null) {
// Handle error when no value was returned
return;
}
postName = value;
});
var uploader = document.getElementById('uploader');
var filebutton = document.getElementById('filebutton');
filebutton.addEventListener('change', function(e) {
if (postName === null) {
// Handle the case then post name is still null (either wan't loaded yet or couldn't be loaded)
return;
}
var file = e.target.files[0];
var ext = file.name.split('.').pop();;
//create a storage ref
var storageRef = firebase.storage().ref('posts/' + postName + "." + ext);
var task = storageRef.put(file);
publishPost(postName, ext);
function publishPost(postName, ext) {
firebase.database().ref('posts/' + postName).set({
postID: postName,
postDate: Date(),
fileType : ext
});
firebase.database().ref('variables/').set({
postNumber: postName + 1
});
}
task.on('state_changed',
function progress(snapshot){
var percentage = (snapshot.bytesTransferred / snapshot.totalBytes) *100;
uploader.value = percentage;
},
function error(err){
},
function complete(postName, ext){
uploader.value = 0;
window.alert('Your meme Uploaded correctly');
});
});
Related
I am working with Firebase Storage and trying to upload multiple files at a time. What I have done so far is, i get the files, and upload one by one to firebase and only one progress bar is there which shows the progress for each uploading file. What I need is, when i select the files, i want to create the progress bars equal to the number of files and they will start uploading and each progress bar will be shown its own progress.
What I have done so far is :
var up = document.getElementById("fileUpload"),
pr = document.getElementsByClassName("progress")[0];
list = document.getElementsByClassName("list")[0];
//Listen for file selection
up.addEventListener('change', function(e){
//Get files
for (var i = 0; i < e.target.files.length; i++) {
var imageFile = e.target.files[i];
uploadImageAsPromise(imageFile,i);
}
});
//Handle waiting to upload each file using promise
function uploadImageAsPromise (imageFile,i) {
return new Promise(function (resolve, reject) {
var storageRef = firebase.storage().ref($.cookie("_lo")+"/"+imageFile.name);
//Upload file
var task = storageRef.put(imageFile);
//Update progress bar
task.on('state_changed',
function progress(snapshot){
var percentage = snapshot.bytesTransferred / snapshot.totalBytes * 100;
pr.value = percentage;
},
function error(err){
},
function complete(){
var downloadURL = task.snapshot.downloadURL;
console.log("file " + (i+1) + " Uplaoded");
console.log(downloadURL);
}
);
});
}
This is the quickest Solution I came with :
var up = document.getElementById("fileUpload"),
pr = document.getElementsByClassName("progress");
list = document.getElementsByClassName("list")[0];
//Listen for file selection
up.addEventListener('change', function(e){
//Get files
for (var i = 0; i < e.target.files.length; i++) {
var imageFile = e.target.files[i];
list.insertAdjacentHTML('afterbegin','<li class="row">'+
'<div class="col-4">'+imageFile.name+'</div>'+
'<div class="col-4">'+imageFile.size+'</div>'+
'<progress value="0" max="100" class="progress"></progress>'+
'</li>');
uploadImageAsPromise(imageFile,i);
}
});
//Handle waiting to upload each file using promise
function uploadImageAsPromise (imageFile,i) {
return new Promise(function (resolve, reject) {
var storageRef = firebase.storage().ref($.cookie("_lo")+"/"+imageFile.name);
//Upload file
var task = storageRef.put(imageFile);
//Update progress bar
task.on('state_changed',
function progress(snapshot){
var percentage = snapshot.bytesTransferred / snapshot.totalBytes * 100;
pr[i].value = percentage;
},
function error(err){
},
function complete(){
var downloadURL = task.snapshot.downloadURL;
console.log("file " + (i+1) + " Uplaoded");
console.log(downloadURL);
}
);
});
}
I would like to execute the code this.createListing() after the for-loop has finished and the upload is complete.
If I run it after the for-loop, it doesn't take into consideration if all the uploads have finished or not. Thus it will not get the downloadURL from the uploaded files.
Ideally I would like to run the function after all uploads are complete.
Any help is appreciated. Here is my code:
submitForm() {
const user = firebase.auth().currentUser
const listingPostKey = firebase.database().ref('listings/').push().key
const listingRef = firebase.database().ref('listings/' + listingPostKey)
for (let i = 0; i < this.uploadedImages.length; i++) {
var storageRef = firebase.storage().ref('images/' + user.uid + '/' + this.imageName)
var uploadTask = storageRef.put(this.uploadedImages[i])
uploadTask.on('state_changed', (snapshot) => {
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
}, error => {
this.errors.push(error.message)
}, () => {
// Upload complete
var downloadURL = uploadTask.snapshot.downloadURL
this.images_url.push(downloadURL)
this.createListing()
})
}
}
According to the docs:
put() and putString() both return an UploadTask which you can use as a promise, or use to manage and monitor the status of the upload.
So you can just use Promise.all to wait for all uploads to be done.
Here is the code I came up with:
submitForm() {
const user = firebase.auth().currentUser
const listingPostKey = firebase.database().ref('listings/').push().key
const listingRef = firebase.database().ref('listings/' + listingPostKey)
const storageRef = firebase.storage().ref('images/' + user.uid + '/' + this.imageName)
// map uploadedImages to array of uploadTasks (promises)
const uploads = this.uploadedImages.map(uploadedImage => {
const uploadTask = storageRef.put(uploadedImage)
// you probably don't need this part
// since 'progress' is not used anywhere
uploadTask.on('state_changed', snapshot => {
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
})
return uploadTask.then(snapshot => {
this.images_url.push(snapshot.downloadURL)
})
})
// wait for all uploadTasks to be done
Promise.all(uploads).then(() => {
this.createListing()
})
}
I get no credit for the code below. It was found online. It works to open a file but I'd need something to display only certain strings withing a file (i.e)
test = 2000
radio 1020
webbrowser - 1000
help needed = 2000
I'd need to modify this to display only, for example, help needed = 2000
<script>
function readBlob(opt_startByte, opt_stopByte) {
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var start = parseInt(opt_startByte) || 0;
var stop = parseInt(opt_stopByte) || file.size - 1;
var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
document.getElementById('byte_content').textContent = evt.target.result;
document.getElementById('byte_range').textContent =
['Read bytes: ', start + 1, ' - ', stop + 1,
' of ', file.size, ' byte file'].join('');
}
};
var blob = file.slice(start, stop + 1);
reader.readAsBinaryString(blob);
}
document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
if (evt.target.tagName.toLowerCase() == 'button') {
var startByte = evt.target.getAttribute('data-startbyte');
var endByte = evt.target.getAttribute('data-endbyte');
readBlob(startByte, endByte);
}
}, false);
</script>
First of all, web browsers does not allow you to access local files using javascript for security reasons.
So, if you really want to read the file in javascript, you should consider setting up an environment to execute javascript. You can read it here. Executing javascript without browser.
I am trying to use firebase to upload a file as well as enter the file in my data base at the same time. (I would like to keep track of how many uploads there are so I can rename the file to something unique) I successfully uploaded, and also put a copy in the database but I can not get a number back of how many files are in the child folder using the once() and getChildren() methods. I keep getting an error. What am I doing wrong? The count number error is coming from here:
var ref = firebase.database();
ref.once("value")
.then(function(snapshot) {
var numberSamples = snapshot.child(sampleType).numChildren(); //number of children
});
Full code:
<script src="https://www.gstatic.com/firebasejs/3.3.2/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyC9jUMxOvvdgcBvXecvpRiactG6ffbwTgg",
authDomain: "instasample-d8eea.firebaseapp.com",
databaseURL: "https://instasample-d8eea.firebaseio.com",
storageBucket: "instasample-d8eea.appspot.com",
};
firebase.initializeApp(config);
//remove error on click
function removeSampleClass() {
$("#sampleType").removeClass('sampleTypeError')
$("#sampleType").addClass('sampleType')
}
function removeFileClass() {
$("#fileButton").removeClass('fileButtonError')
$("#fileButton").addClass('fileButton')
}
// upload files and check for errors
function uploadFile(){ //on GO
//get elements
var uploader = document.getElementById('uploader')
var fileButton = document.getElementById('fileButton')
//var file = fileButton.target.files[0]; //get file
var sampleType = document.getElementById('sampleType').options[document.getElementById('sampleType').selectedIndex].text; //get folder location
var file = fileButton.files[0]; //get file
if (sampleType == "Select Type" && fileButton.value == "") { //check both selection
$("#sampleType").addClass('sampleTypeError')
$("#sampleType").removeClass('sampleType')
$("#fileButton").addClass('fileButtonError')
$("#fileButton").removeClass('fileButton')
}
else if (fileButton.value == "") { //check file selection
$("#fileButton").addClass('fileButtonError')
$("#fileButton").removeClass('fileButton')
}
else if (sampleType == "Select Type") { //check sample selection
$("#sampleType").addClass('sampleTypeError')
$("#sampleType").removeClass('sampleType')
}
else{ //upload if good
uploader.classList.remove('hide'); //unhide progress bar
//create storage reference with sampleType
var storageRef = firebase.storage().ref("/" + sampleType + "/" + file.name);
//upload file
var task = storageRef.put(file);
//update progress bar
task.on('state_changed',
function progress(snapshot){
var percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
uploader.value = percentage;
},
function error() {
alert('There was a problem uploading your file')
},
function complete() {
//get root reference
const dbRefType = firebase.database().ref().child(sampleType);
var ref = firebase.database();
ref.once("value")
.then(function(snapshot) {
var numberSamples = snapshot.child(sampleType).numChildren(); // 2 ("first", "last")
});
var updates = {};
updates["/" + sampleType + "/" + sampleType + "Sample" + numberSamples ] = numberSamples;
return firebase.database().ref().update(updates);
//sync data and return children of sampleType to console
//dbRefType.on('value', snap => console.log(snap.val()));
//create new reference to file
//var sampleFileRef = dbRefType.child("sample");
//TODO: list how many are in list
//add new file to list
}
);
}
}
</script>
nevermind, I got it. used
dbRefType.once('value', function(snapshot) { alert('Count: ' + snapshot.numChildren()); });
I want to build a voice recorder using HTML5 same as one found in gitHub JSSoundecorder, but what I want is for the user to be able to choose the file format before recording the voice.I can do this using ffmpeg. In other words the user must be able to select the audio format by check box (mp3,wma,pcm) and in the background code, the .wav file usually created by the program instead of displaying it, it should be converted by the format selected then displayed in the new format.this is the ffmpeg code we can use ,but I don't know how to get the .wav audio file to convert it and show it.please if someone have ideas,or if can find demos I have been looking for weeks.this is the ffmpeg code:
var fileName;
var fileBuffer;
function timeToSeconds(time) {
var parts = time.split(":");
return parseFloat(parts[0]) * 60 * 60 + parseFloat(parts[1]) * 60 + parseFloat(parts[2]) + parseFloat("0." + parts[3]);
}
// create ffmpeg worker
function getFFMPEGWorker() {
// regexps for extracting time from ffmpeg logs
var durationRegexp = /Duration: (.*?), /
var timeRegexp = /time=(.*?) /;
var duration;
var ffmpegWorker = new Worker('worker.js');
var durationLine;
ffmpegWorker.addEventListener('message', function(event) {
var message = event.data;
console.log(message.type);
if (message.type === "ready" && window.File && window.FileList && window.FileReader) {
// script loaded, hide loader
$('#loading').hide();
} else if (message.type == "stdout") {
console.log(message.data);
} else if (message.type == "stderr") {
console.log(message.data);
// try to extract duration
if (durationRegexp.exec(message.data)) {
duration = timeToSeconds(durationRegexp.exec(message.data)[1]);
}
// try to extract time
if (timeRegexp.exec(message.data)) {
var time = timeToSeconds(timeRegexp.exec(message.data)[1]);
if (duration) {
$("#progress").text("Progress: " + Math.floor(time / duration * 100) + "%");
$("#progress").show();
}
}
} else if (message.type == "done") {
var code = message.data.code;
console.log(message.data);
var outFileNames = Object.keys(message.data.outputFiles);
console.log(outFileNames);
if (code == 0 && outFileNames.length) {
var outFileName = outFileNames[0];
var outFileBuffer = message.data.outputFiles[outFileName];
var src = window.URL.createObjectURL(new Blob([outFileBuffer]));
$("#downloadLink").attr('href', src);
$("#download").show();
} else {
$("#error").show();
}
$("#converting").hide();
$("#progress").hide();
}
}, false);
return ffmpegWorker;
}
// create ffmpeg worker
var ffmpegWorker = getFFMPEGWorker();
var ffmpegRunning = false;
$('#convert').click(function() {
// terminate existing worker
if (ffmpegRunning) {
ffmpegWorker.terminate();
ffmpegWorker = getFFMPEGWorker();
}
ffmpegRunning = true;
// display converting animation
$("#converting").show();
$("#error").hide();
// hide download div
$("#download").hide();
// change download file name
var fileNameExt = fileName.substr(fileName.lastIndexOf('.') + 1);
var outFileName = fileName.substr(0, fileName.lastIndexOf('.')) + "." + getOutFormat();
$("#downloadLink").attr("download", outFileName);
$("#downloadLink").text(outFileName);
var arguments = [];
arguments.push("-i");
arguments.push(fileName);
arguments.push("-b:a");
arguments.push(getBitrate());
switch (getOutFormat()) {
case "mp3":
arguments.push("-acodec");
arguments.push("libmp3lame");
arguments.push("out.mp3");
break;
case "wma":
arguments.push("-acodec");
arguments.push("wmav1");
arguments.push("out.asf");
break;
case "pcm":
arguments.push("-f");
arguments.push("s16le");
arguments.push("-acodec");
arguments.push("pcm_s16le");
arguments.push("out.pcm");
}
ffmpegWorker.postMessage({
type: "command",
arguments: arguments,
files: [
{
"name": fileName,
"buffer": fileBuffer
}
]
});
});
function getOutFormat() {
return $('input[name=format]:checked').val();
}
function getBitrate() {
return $('input[name=bitrate]:checked').val();
}
// disable conversion at start
$('#convert').attr('disabled', 'true');
function readInputFile(file) {
// disable conversion for the time of file loading
$('#convert').attr('disabled', 'true');
// load file content
var reader = new FileReader();
reader.onload = function(e) {
$('#convert').removeAttr('disabled');
fileName = file.name;
console.log(fileName);
fileBuffer = e.target.result;
}
reader.readAsArrayBuffer(file);
}
// reset file selector at start
function resetInputFile() {
$("#inFile").wrap('<form>').closest('form').get(0).reset();
$("#inFile").unwrap();
}
resetInputFile();
function handleFileSelect(event) {
var files = event.target.files; // FileList object
console.log(files);
// files is a FileList of File objects. display first file name
file = files[0];
console.log(file);
if (file) {
$("#drop").text("Drop file here");
readInputFile(file);
}
}
// setup input file listeners
document.getElementById('inFile').addEventListener('change', handleFileSelect, false);