Download mp3 file from url with xmlHttpRequest and writing it to file - javascript

I've currently tried every possible ways to do this but I cannot get it to work, despite reading every related question on the internet ...
I'm simply trying to download an mp3 arrayBuffer that i GET from an url with the module xmlHttpRequest from my node server code with the intent to then writing the buffer to an mp3 file, here is the code:
const endpoint = "https://cdns-preview-a.dzcdn.net/stream/c-ae4124ee0e63b9f6abffddb36b9695cf-2.mp3";
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var oReq = new XMLHttpRequest();
oReq.open("GET", endpoint, true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
if (this.status != 200) {
console.log(this.status)
}
console.log(oReq.response);
var uInt8Array = new Uint8Array(oReq.response);
console.log(uInt8Array);
var dest = "1.mp3";
var stream = fs.createWriteStream(dest);
stream.write(uInt8Array);
stream.end();
}
};
oReq.send();
oReq.response is always empty, no matter what I type in oReq.responseType(arraybuffer, blob).
if I try to write oReq.responseText, it's always going to be some scuffed encoding because it was translated to text.
Can you give me advices, is there some underlying deep layer that I don't understand, is it possible to do what I wanna achieve?

Found a solution with http get instead of xmlHttpRequest:
const endpointe = "https://cdns-preview-a.dzcdn.net/stream/c-ae4124ee0e63b9f6abffddb36b9695cf-2.mp3";
https.get(endpointe, (res) => {
datatest = []
res.on('data', function(chunk) {
datatest.push(chunk);
console.log(chunk);
});
// The whole response has been received. Print out the result.
res.on('end', () => {
//console.log(data)
var dest = "test.mp3";
var stream = fs.createWriteStream(dest);
var buffer = Buffer.concat(datatest);
stream.write(buffer);
stream.end();
});
}).on('error', (e) => {
console.error(e);
});

Related

XMLHTTPrequest plain text to blob (video)

I achieved to get a video from php using this code :
var some_video_element = document.querySelector('video')
var req = new XMLHttpRequest();
req.onload = function () {
var blob_uri = URL.createObjectURL(this.response);
some_video_element.src = blob_uri;
some_video_element.addEventListener('oncanplaythrough', (e) => {
URL.revokeObjectURL(blob_uri);
});
};
req.open("get", "vid.php", true);
req.overrideMimeType('blob');
req.send(null);
However, the loading is long so I want to show data as soon as I get it. From Mozilia, it is indicated we can use plain or "" as mime to get the text in progress. However, I can't achieve to convert plain/text to video/mp4 using a blob. Currently this is the code that doesn't work. I try to get the video when some part is available while the rest is still downloading.
var some_video_element = document.querySelector('video')
var req = new XMLHttpRequest();
req.onprogress = function () {
var text = b64toBlob(Base64.encode(this.response), "video/mp4");
var blob_uri = URL.createObjectURL(text);
some_video_element.src = blob_uri;
some_video_element.addEventListener('oncanplaythrough', (e) => {
URL.revokeObjectURL(blob_uri);
});
};
req.onload = function () {
var text = b64toBlob(this.response, "video/mp4");
var blob_uri = URL.createObjectURL(text);
some_video_element.src = blob_uri;
some_video_element.addEventListener('oncanplaythrough', (e) => {
URL.revokeObjectURL(blob_uri);
});
};
req.open("get", "vid.php", true);
req.overrideMimeType('text\/plain');
req.send(null);
Thanks.
NB : This JavaScript is fetching for this php code : https://codesamplez.com/programming/php-html5-video-streaming-tutorial
But echo data has been changed by echo base64_encode(data);
If you use the Fetch API instead of XMLHttpRequest you can consume the response as a ReadableStream which can be fed into a SourceBuffer. This will allow the video to be playable as soon as it starts to load instead of waiting for the full file to download. This does not require any special video container formats, back-end processing or third-party libraries.
const vid = document.getElementById('vid');
const format = 'video/webm; codecs="vp8,vorbis"';
const mediaSource = new MediaSource();
let sourceBuffer = null;
mediaSource.addEventListener('sourceopen', event => {
sourceBuffer = mediaSource.addSourceBuffer(format);
fetch('https://bes.works/dev/samples/test.webm')
.then(response => process(response.body.getReader()))
.catch(err => console.error(err));
}); vid.src = URL.createObjectURL(mediaSource);
function process(stream) {
return new Response(
new ReadableStream({
start(controller) {
async function read() {
let { done, value } = await stream.read();
if (done) { controller.close(); return; }
sourceBuffer.appendBuffer(value);
sourceBuffer.addEventListener(
'updateend', event => read(),
{ once: true }
);
} read();
}
})
);
}
video { width: 300px; }
<video id="vid" controls></video>
As indicated in the comments, you are missing some decent components.
You can implement what you are asking for but you need to make some changes. Following up on the HTML5 streaming API you can create a stream that will make the video using segments you fetch from the server.
Something to keep in mind is the HLS or DASH protocol that already exists can help, looking at the HLS protocol can help as it's simple to use with the idea of segments that can reach out to your server and just decode your base64'd feed.
https://videojs.github.io/videojs-contrib-hls/

Read the excel file from the specific location

I don't want to use this way(link)
because I don't want to open new window for file selection.
I just want to load & read excel file when I click some button.
But this is not work.. help me to load the excel file.
MYCODE:
const FILE_NAME = "C:/Users/A/project_list.xlsx";
function LoadSpread(json) {
jsonData = json;
workbook.fromJSON(json);
workbook.setActiveSheet("Revenues (Sales)");
}
function excelExport(fileName) {
console.log(fileName);
var excelUrl = fileName;
var oReq = new XMLHttpRequest();
oReq.open("get", excelUrl, true);
oReq.responseType = "blob";
oReq.onload = function() {
var blob = oReq.response;
excelIO.open(blob, LoadSpread, function(message) {
console.log(message);
});
};
oReq.send(null);
}
function chkPrtNum(event) {
var fileName = FILE_NAME;
excelExport(fileName);
}
Try creating a small server for the same, you will easily get your job done. – Raghu Chahar Jan 28 at 9:50
This was very helpful

Javascript Read Excel file on server with SheetJS

I am using a library called SheetJS and I want to read an excel sheet that resides on the server without using nodejs, only pure javascript. Is this possible?
There is a message in the documentation that says "readFile is only available in server environments. Browsers have no API for reading arbitrary files given a path, so another strategy must be used"
With the above message, I assume the author is referring to a situation where the file is residing on the client side.
This is what I have done so far
var wb = XLSX.readFile("myFile.xlsx"); //my file is in same directory on server
I get error "xlsx.full.min.js:22 Uncaught TypeError: Cannot read property 'readFileSync' of undefined"
This worked for me
/* set up async GET request */
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";
req.onload = function(e) {
var data = new Uint8Array(req.response);
var workbook = XLSX.read(data, {type:"array"});
/* DO SOMETHING WITH workbook HERE */
}
req.send();
I had many issues with reading the file server-side, with a number of errors including type error, charCodeAt. So this provides a client and server-side solution using a reader. The excel file comes from a file upload button, and uses node.js.
Client-side:
let excelInput = document.getElementById("fileToUpload");
let excelFile = excelInput.files[0];
let reader = new FileReader();
So you get the file using files[0] from that element and create a fileReader.
You can see Aymkdn's solution on Github. https://github.com/SheetJS/sheetjs/issues/532. It uses the Uint8Array to work.
reader.readAsArrayBuffer(excelFile);
reader.onload = function() {
excelArray = new Uint8Array(reader.result); //returns Uint8Array using the result of reader
let binary = "";
var length = excelArray.byteLength;
for (var i = 0; i < length; i++) {
binary += String.fromCharCode(excelArray[i]);
//uses a for loop to alter excelArray to binary
}
let formData = new FormData(); //create form data
formData.append("excel", binary); //append binary to it
fetch('/excel', {method: "POST", body: formData}) //post as normal
.then((data) => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
}
Server-side:
app.post('/excel', function(req, res) {
let data = req.body;
var workbook = sheetJS.read(data, {type: 'buffer'});
console.log("workbook is", workbook);
res.send();
}

facing a CORS error

I'm facing a CORS error when I'm trying to download video from different domain. I tried a lot to solve it but couldn't.
Below is my js code.
getVideoFile = function () {
var xhr = new XMLHttpRequest(),
blob;
xhr.open("GET",myVideo, true);
xhr.responseType = "blob";
xhr.addEventListener("load", function () {
if (xhr.status === 200) {
blob = xhr.response;
putVideoInDb(blob);
window.alert("Video file downloaded");
}
else {
window.alert("Unable to download video");
}
}, false);
xhr.send();
};
putVideoInDb = function (blob) {
var transaction = db.transaction(["Videos"], "readwrite");
var store = transaction.objectStore("Videos");
var vid = {
videoName:videoName,
video:blob,
}
var request = store.add(vid);
request.onerror = function(e) {
console.log("Error",e.target.error.name);
}
request.onsuccess = function(e) {
console.log("Done!!");
}
};
xhr.setRequestHeader('Access-Control-Allow-Headers', '*');
Set this header value before sending your request. For more information you can read here JavaScript - XMLHttpRequest, Access-Control-Allow-Origin errors
Take a look at this question: CORS error on same domain?
Of course this is a scenario where the domain is the same, but however the logic's the same...
There's a lot of articles out there about this topic.

Why does AJAX output comes with wrong encoding?

I'm getting a file from a server with AJAX (Angular).The file is a simple XLSX document, sent like this:
ob_start();
$file = \PHPExcel_IOFactory::createWriter($xls, 'Excel2007');
$file->save('php://output');
$response->setContent(ob_get_clean());
$response->headers->replace(array(
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'Content-Disposition' => 'attachment;filename=file.xlsx"'
));
When I make a request from frontend, I use Accept header too. Then I save the file with angular-file-saver using FileSaver.js and Blob.js.
But the received file is corrupt and I can't open it in Excel: it's size is (for example) 12446 bytes, but Chrome's DevTools Network tab shows responses Content-Length header as 7141 bytes.
How can I solve this problem?
UPD:
I'm sending a request like this:
$http.get(baseURL + '/' + entity + '/export/?' + condition + sort, {
headers: {'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8'}
});
and downloading file just like this:
var data = new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'});
FileSaver.saveAs(data, 'file.xlsx');
The way I got around the problem was using plain JS AJAX, instead of AngularJS. (There might be a problem with AngularJS and JQuery handling binary responses.)
This should work:
var request = new XMLHttpRequest();
request.open('GET', 'http://yourserver/yourpath', true);
request.responseType = 'blob';
request.onload = function (e) {
if (this.status === 200) {
var blob = this.response;
if (window.navigator.msSaveOrOpenBlob) {
var fileNamePattern = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
window.navigator.msSaveBlob(blob, fileNamePattern.exec(request.getResponseHeader("content-disposition"))[1]);
} else {
var downloadLink = window.document.createElement('a');
var contentTypeHeader = request.getResponseHeader("Content-Type");
var b = new Blob([blob], { type: contentTypeHeader });
downloadLink.href = window.URL.createObjectURL(b);
var fileNamePattern = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
downloadLink.download = fileNamePattern.exec(request.getResponseHeader("content-disposition"))[1];
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
window.URL.revokeObjectURL(b);
}
}
};
request.send();
Code is based on this and this.
FYI, I found that new Blob([response.data], ...) returns almost double the size of response.data when response.data is not returned as blob, but text/plain or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet. To get around it, you need to pass it an array of bytes instead:
var i, l, d, array;
d = this.result;
l = d.length;
array = new Uint8Array(l);
for (var i = 0; i < l; i++){
array[i] = d.charCodeAt(i);
}
var b = new Blob([array], {type: 'application/octet-stream'});
window.location.href = URL.createObjectURL(b);
Code is from here.
Anyways, since the AJAX response is not correct using AngularJS, you won't get a valid xlsx file this way. You need to go with vanilla JS.

Categories

Resources