I'm currently playing an audio file using an external URL:
const url = 'http://s5.qhres.com/static/465f1f953f1e6ff2.mp3';
const audio = new Audio(url);
audio.play();
How can I programmatically upload this file to the node server? (so the mp3 file can be stored in the server)
Should I get the audio data and send it to the server using fetch()?
Some guidance would be appreciated.
This is how you can implement an upload function to upload your audioFile
first we download the file turn it into binary
second we uploaded
For the backend in nodejs you can use multer with express to setup and upload API so you can receive the file this is a guide that can help you
TBN : Read the code comment and you will understand how it works
// load status span
let Status = document.getElementById("status");
// messages for status
const DOWN_START = "File is being downloaded ...";
const DOWN_SUCCESS = "File is downloaded ...";
const DOWN_FAIL = "File failed to download with : ";
const UPLOAD_START = "File is being Uploaded ";
const UPLOAD_SUCCESS = "File is Uploaded";
const UPLOAD_FAILD = "File failed to upload with : ";
// function to update status span
const updateStatusMsg = (msg) => {
Status.innerHTML = msg;
};
// instansiate XMLHttpRequest
let downloadReq = new XMLHttpRequest();
let fileUrl = null;
// XMLHttpRequest Progress Listeners
downloadReq.addEventListener("progress", () => updateStatusMsg(DOWN_START));
downloadReq.addEventListener("load", () => updateStatusMsg(DOWN_SUCCESS));
downloadReq.addEventListener("error", () => updateStatusMsg(DOWN_FAIL));
// Grab url from input
const getUrl = (self) => {
fileUrl = self.value;
};
// Download File
const getFile = () => {
// [TIP] here i added a proxy for the app so you can have a valid cors so it can work locally
downloadReq.open(
"GET",
"https://api.allorigins.win/get?url=" + encodeURIComponent(fileUrl),
true
);
downloadReq.responseType = "blob";
// Setup listener onLoad
downloadReq.onload = function () {
//When the file is downloaded we pass it to the upload function
uploadFile(downloadReq.response);
// if you want also to read the file and play it you can use this
let reader = new FileReader();
reader.readAsDataURL(downloadReq.response);
reader.onload = function (e) {
console.log(reader);
console.log("DataURL:", e.target.result);
};
};
// Start Request
downloadReq.send();
};
// Upload
const uploadFile = (blob) => {
// Create A file
let audioFile = new File([blob], "audioFile");
updateStatusMsg(UPLOAD_START);
// Sending Using fetch here you can add your node.js End point
fetch("http://www.example.net", {
method: "POST",
headers: {
"Content-Type": "Your Content Type",
},
body: audioFile,
})
.then((response) => response.json())
.then((success) => updateStatusMsg(UPLOAD_SUCCESS))
.catch((error) => updateStatusMsg(UPLOAD_FAILD + error.message));
};
<input type="text" placeholder="Enter the file link" onchange="getUrl(this)" />
<input type="button" value="Upload File" onClick="getFile()" />
<br />
<span id="status"></span>
Related
I have code where I can download the file form URL but I need the file to have the same name as per original file name where it was uploaded
const downloadImage = () => {
var http = require("http"),
Stream = require("stream").Transform,
fs = require("fs");
var url = "http://cutt.ly/0JCQfSh";
http
.request(url, function (response) {
var data = new Stream();
response.on("data", function (chunk) {
data.push(chunk);
});
response.on("end", function () {
fs.writeFileSync('image.png', data.read());
});
})
.end();
};
Open the URL Link on the browser and check the file name its Asset0.png. I want to download a file with the same name
I'm trying to upload a base64encoded image to Cloudinary using the following code. However, this code doesn't work. Could you guys suggest to me any solution for this, please? The post request fails with a 500 error.
const uploadProductImage = asyncHandler(async (req, res) => {
let image = req.body.image;
const cloudres = await cloudinary.v2.uploader.upload(image);
console.log(cloudres);
res.status(200);
});
Not sure if this helps, but here is a working codepen uploading a base64 encoded file.
Update the cloudname and unsigned preset to your information. Refresh the codepen and it will upload into your cloud account.
https://codepen.io/tmero/pen/poeXaPY
const cloudName = 'tessamero';
const unsignedUploadPreset = 'stackoverflowtest';
// Upload base64 encoded file to Cloudinary
uploadFile('data:image/gif;base64,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')
// *********** Upload file to Cloudinary ******************** //
function uploadFile(file) {
var url = `https://api.cloudinary.com/v1_1/${cloudName}/upload`;
var xhr = new XMLHttpRequest();
var fd = new FormData();
xhr.open('POST', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(e) {
if (xhr.readyState == 4 && xhr.status == 200) {
// File uploaded successfully
var response = JSON.parse(xhr.responseText);
// https://res.cloudinary.com/cloudName/image/upload/v1483481128/public_id.jpg
var url = response.secure_url;
// Create a thumbnail of the uploaded image, with 150px width
var tokens = url.split('/');
tokens.splice(-2, 0, 'w_150,c_scale');
var img = new Image(); // HTML5 Constructor
img.src = tokens.join('/');
img.alt = response.public_id;
document.body.appendChild(img);
}
};
fd.append('upload_preset', unsignedUploadPreset);
fd.append('tags', 'browser_upload'); // Optional - add tag for image admin in Cloudinary
fd.append('file', file);
xhr.send(fd);
}
An alternative, here is a great developer post on uploading base64encoded images with nodejs using Cloudinary by James Quick: https://dev.to/jamesqquick/cloudinary-image-upload-with-nodejs-4mad
Let me know if any of this helps!
const cloudinary = require('cloudinary').v2;
const { CloudinaryStorage } = require('multer-storage-cloudinary');
const express = require('express');
const multer = require('multer');
const app = express();
const storage = new CloudinaryStorage({
cloudinary: cloudinary,
params: {
folder: 'some-folder-name',
format: async (req, file) => 'png', // supports promises as well
public_id: (req, file) => 'computed-filename-using-request',
},
});
const parser = multer({ storage: storage });
app.post('/upload', parser.single('image'), function (req, res) {
res.json(req.file);
});
I'm building an app for my friend and I need to record audio and store it on a server. I have successfully done it with text and images, but I can't make it work for audio.
I am probably missing something when creating the file (the file is created but not playable). There has to be a problem with the data conversion from the JS Blob to the actual file.
I managed to get the audio blob and even play it back in JS. But when I create a file from the blob it can't be played (I tried to save it locally with the same outcome - got the file but could not play it). I also tried to save it in different formats with no success (wav, mp3). So the problem has to be in the conversion from the blob to the actual file. With text and images, it was straightforward forward and the files were created from the blob just by saving them with a filename. But I guess that with audio isn't that simple.
My understanding is that I have some binary data (JS Blob), that can be saved as a file. But with audio, there has to be some special conversion or encoding so the output file works and can be played.
here is the frontend code (I am using this with some of the variables because its part of a Vue component)
this.mediaRecorder.addEventListener("stop", () => {
// tried to save it as WAV with the same result got the file, but couldn't play it
this.audioBlob = new Blob(this.audioChunks, { 'type' : 'audio/mpeg-3' })
//debugging - playing back the sound in the browser works fine
const audioUrl = URL.createObjectURL(this.audioBlob);
const audio = new Audio(audioUrl);
audio.play();
//adding the blob to the request
let filename = this.$store.state.counter + "-" + this.$store.state.step
const formData = new FormData();
formData.append('file', this.audioBlob, `${filename}.mp3`);
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
//sending it to my Flask API (xxx is the name of the folder it gets saved to on the server)
this.$axios.post('http://localhost:5000/api/v1/file/upload/xxx', formData, config)
})
here is my endpoint on the server
#app.route('/api/v1/file/upload/<test_id>', methods=['POST'])
def upload_file(test_id):
uploaded_file = request.files['file']
filename = secure_filename(uploaded_file.filename)
if filename != '':
uploaded_file.save(os.path.join(app.config['UPLOAD_PATH'], test_id, filename))
return jsonify({'message': 'file saved'})
Here is the whole recording code snippet
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
this.mediaRecorder = new MediaRecorder(stream);
// audio.srcObject = stream
this.mediaRecorder.start();
this.mediaRecorder.addEventListener("dataavailable", event => {
this.audioChunks.push(event.data)
})
this.mediaRecorder.addEventListener("stop", () => {
this.audioBlob = new Blob(this.audioChunks, { 'type' : 'audio/mpeg-3' })
//debugging - playing back the sound in the browser works fine
const audioUrl = URL.createObjectURL(this.audioBlob);
const audio = new Audio(audioUrl);
audio.play();
//adding the blob to the request
let filename = this.$store.state.counter + "-" + this.$store.state.step
const formData = new FormData();
formData.append('file', this.audioBlob, `${filename}.mp3`);
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
//sending it to my Flask API (xxx is the name of the folder it gets saved to on the server)
this.$axios.post('http://localhost:5000/api/v1/file/upload/xxx', formData, config)
})
})
I'm using the gcloud API on a Nodejs web server to upload files. I'd prefer the files not be uploaded on the client side and instead uploaded on the server. Currently, I am producing a blob on the client side, then converting it to text and passing that to the server through a POST request. All of the information gets successfully passed from the client to the server as expected. This data is also uploaded to gcloud, however, Gcloud does not recognize this as a valid file nor does my computer when I download it.
What is the best way to get the contents of the file to gcloud from the server side? I've tried using dataURIs and reading the orignal file by text and both produce similiar issues. I've also explored piping a readFileStream from the blob on the server end but blobs are not natively supported by node so I have not done so yet.
Client Side
function readSingleFile(e, func, func2){
var file = e.target.files[0];
if(!file){
return; // Add error msg_here
}
var reader = new FileReader();
reader.onload = function(e){
let contents = e.target.result;
let img = document.createElement('img')
let cvs = document.createElement('canvas');
img.onload = ()=>{
cvs.width = img.width;
cvs.height= img.height;
let ctx = cvs.getContext('2d');
ctx.drawImage(img,0,0);
cvs.toBlob((res)=>{res.text().then((text)=>{func2(text)})}, "image/jpeg", 0.92);
}
img.src=contents;
func(contents);
}
reader.readAsDataURL(file);
}
Server Side
function publishPrintjob(dataObj){
try{
var newElemKey = database.ref().child('queue').push().key; // Get random Key
// Create a new blob in the bucket and upload the file data.
const gcloudFile = storage.file('images/' + newElemKey + '.jpg');
gcloudFile.save(dataObj.sockImageFile, function(err) {
if (!err) {
Console.log("File Uploaded!")
}
});
var data = {
date: dataObj.Date,
email: dataObj.email,
design: dataObj.Design,
author: dataObj.Author,
address: dataObj.address,
imageKey: newElemKey,
}
admin.database().ref('queue/' + newElemKey).set(data);
} catch(err){
console.log(err)
}
}
Note: func simply shows the image on the client side, func2 just adds the contents to the POST object.
Uploading a file directly from the computer would be easiest using the storage.bucket(bucketName).upload() function from the cloud storage library. However, this uses location of a file locally and thus will not work unless a file is transferred to the server and saved first. This could be achieved using multi-part form data. Using multipart or uploading locally are better methods for uploading to google storage.
Instead, I solve this by first converting the image to a dataURI, sending the data URI to the server via the body of a GET request, and then converting it to a buffer with a readable stream that can be piped to google storage.
Client
let formData = getFormData('myForm');
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
}
};
xhttp.open("POST", "dashboard", true);
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(JSON.stringify(formData));
xhttp.onload = ()=> {
console.log(JSON.parse(xhttp.response))
// Handle server response here
};
}
Server
// DataObject is the body of the GET request, the property imageFile is the URI from readFileAsURI
function uploadImageOnServer(dataObj){
try{
var newElemKey = database.ref().child('queue').push().key; // Get random Key to use as filename
// Create a new blob in the bucket and upload the file data.
const gcloudFile = storage.file('images/' + newElemKey + '.jpeg');
var fs = require('fs'); // Should be required at the top of the file
var string = dataObj.ImageFile;
var regex = /^data:.+\/(.+);base64,(.*)$/;
var matches = string.match(regex);
var ext = matches[1];
var data = matches[2];
var buffer = Buffer.from(data, 'base64');
// Create the readstream
const readableInstanceStream = new Readable({
read() {
this.push(buffer);
this.push(null);
}
});
readableInstanceStream.pipe(gcloudFile.createWriteStream()) // link to gcloud storage api
.on('error', function(err) {
console.log('error')
})
.on('finish', function() {
console.log('upload complete')
});
} catch(err){
console.log(err)
}
}
I have set up in an SPA application the ability to send files to Azure Blob Storage.
To do this I used XMLHttpRequest and FormData (my users are on computers managed by my company and all have access to HTML5).
In order to manage security, the sending of each file is preceded by a call to a method of a Web Api to obtain the shared access signature.
I forward the Content-Type of the file as well as other information to headers.
Everything happens for the better, the files are correctly sent and saved in Azure Blob Storage, but during the transfer, the image files seem to be "altered".
They are well present, I can download them and read them after the download, but I can not open them directly from an img tag.
On the other hand if I send the same image file via Microsoft Azure Storage Explorer, there is no problem, the image is well recognized in the img tag.
However, in one case as in the other, the content-type is marked as "image / jpeg". The only noticeable difference is that the MD5 is not the same between these 2 mailings while it is the same file of origin.
From my findings it seems that there is text added to the beginning and the end of the file when sending via XMLHttpRequest.
I explain my code so that you can guide me:
Note 1 : I use typescript (but a javascript solution will suit me) and Promise.
Note 2 : I have resolve all the CORS problems.
Note 3 : I'm using Azure Storage Emulator, but i try with the normal Azure service and the problem is the same.
Here is the text added in the image in Chrome:
------WebKitFormBoundaryKj5cK88faAwJd4av
Content-Disposition: form-data; name="file1"; filename="test.jpg"
Content-Type: image/jpeg
[image content]
------WebKitFormBoundaryKj5cK88faAwJd4av--
My Web Api :
[Route(#"api/Storage/FileSas/Customers/{id:int}")]
public async Task<IHttpActionResult> GetFileSas(int id, string fileName, long? fileSize = 0, string contentType = null)
{
if (string.IsNullOrWhiteSpace(fileName))
this.ModelState.AddModelError("fileName", "File name i");
if (!fileSize.HasValue || fileSize.Value > maxFileSize)
this.ModelState.AddModelError("fileSize", "File size exceeded");
if (!this.ModelState.IsValid)
return BadRequest(this.ModelState);
var serverUrl = ConfigurationManager.AppSettings[SERVER_URL];
var container = ConfigurationManager.AppSettings[CONTAINER_NAME];
SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Write,
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-60),
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(60),
};
CloudBlockBlob blobFile = blobContainer.GetBlockBlobReference(Path.Combine("customers", id.ToString(), fileName));
var exists = await blobFile.ExistsAsync();
if (exists)
{
await blobFile.SnapshotAsync();
}
var signature = blobFile.GetSharedAccessSignature(policy);
return Content<string>(HttpStatusCode.Created, Path.Combine(serverUrl, container, blobFile.Name + signature));
}
My TypeScript file :
context.Storage.getFileSas(customerId, file)
.then((response: Interfaces.Result<string>) => {
let sasUrl = response.Data;
let formData = new FormData();
formData.append("file1", file, file.name);
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = (event) => {
if (event.total > 0)
this.Progress(event.loaded * 100 / event.total);
};
xhr.onloadstart = function (e) {
}
xhr.onloadend = (e) => {
this.Progress(0);
}
xhr.open("PUT", sasUrl, true);
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
xhr.setRequestHeader('Content-Type', file.type);
xhr.setRequestHeader('x-ms-blob-content-type', file.type);
xhr.setRequestHeader('x-ms-version', "2016-05-31");
xhr.setRequestHeader('x-ms-meta-CustomerId', customerId);
xhr.setRequestHeader('x-ms-meta-UserId', context.User.User.Id.toString());
xhr.setRequestHeader('x-ms-meta-UserName', context.User.User.Name);
xhr.send(formData);
})
})).catch((error) => {
console.log(error);
});
File come from here :
let fileInputElement1: HTMLInputElement = <HTMLInputElement>document.getElementById("file1");
let file = fileInputElement1.files[0];
My HTML part : (i'm using knockout)
<form method="put" target="_blank" enctype="multipart/form-data">
<input type="file" name="name" value="" id="file1" />
<button data-bind="click:send"> Send</button>
</form>
If someone have an idea ? ...
Thank's in advance.
PS : sasUrl is like this : http://127.0.0.1:10000/devstoreaccount1/customers/65143/test.jpg?sv=2016-05-31&sr=b&sig=s0671%2BLvCZTqyNfhlCthZW8KftjKyIMAlOT1nbsnlng%3D&st=2017-03-05T11%3A38%3A22Z&se=2017-03-06T12%3A38%3A22Z&sp=r&rsct=image%2Fjpeg
Thank's to Gaurav Mantri, he point me to the right, here my modifications (only because i use typescript) :
context.Storage.getFileSas(customerId, file)
.then((response: Interfaces.Result<string>) => {
let sasUrl = response.Data;
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = (event) => {
if (event.total > 0)
this.Progress(event.loaded * 100 / event.total);
};
xhr.onloadstart = function (e) {
}
xhr.onloadend = (e) => {
this.Progress(0);
}
let reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = (event) => {
let target = <FileReader>event.target;
if (target.readyState == reader.DONE) {
var requestData = new Uint8Array(target.result);
xhr.open("PUT", sasUrl, true);
xhr.responseType = "blob";
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('X-File-Name', file.name);
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');
xhr.setRequestHeader('x-ms-blob-content-type', file.type || 'application/octet-stream');
xhr.setRequestHeader('x-ms-version', "2016-05-31");
xhr.setRequestHeader('x-ms-meta-CustomerId', customerId);
xhr.setRequestHeader('x-ms-meta-UserId', context.User.Id.toString());
xhr.setRequestHeader('x-ms-meta-UserName', context.User.Name);
xhr.send(requestData);
}
}
})
})).catch((error) => {
console.log(error);
});
Now i'll start to write a Promise to embedded this fonctionality.
PS : i didn't find the way to mark the Gaurav Mantri as answer so i create mine.
PS 2 : I'll like to put some +1 to Gaurav Mantri for the help... but i can't :/