Not sure what am I doing wrong...
I have a node js webserver that should save a mp3 file to disk from an ajax post. The post contains an mp3 file constructed from a wav file created by recorder.js in the browser.
In my requestHandler I have the following code:
var
formidable = require('formidable'),
http = require('http'),
path = require('path'),
fs = require('fs');
function requestHandler(req, res) {
var requestPath = path.basename(req.url) || 'index.html',
ext = path.extname(requestPath),
localFolder = __dirname + '/public/',
uploadFolder = __dirname + '/uploads/';
if(requestPath === 'uploadmp3' && req.method === 'POST') {
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
if(err) {
console.error(err.message);
return;
}
var mp3File = uploadFolder + fields.fname;
var base64File = new Buffer(fields.data, 'binary').toString('base64');
var decodedFile = new Buffer(base64File, 'base64').toString('binary');
fs.writeFileSync(mp3File, decodedFile, 'base64', function(err){
if(err) {
return console.log(err);
}
console.log('written to disk: ' + mp3File);
});
res.writeHead(200, {'Content-Type:' : 'text/plain'});
res.write(mp3File+ ' \n\n');
res.end('\n');
});
return;
}
}
The result is that I save the file to disk, but although it has the correct size, the time is not set properly and the playback last for one second.
I can save it with php with no problem... mp3 file plays perfectly, but I really need this to work on node js.
You need to use Stream to save contents to disk. As per your implementation:
var fs = require('fs');
if(requestPath === 'uploadmp3' && req.method === 'POST') {
var mp3File = uploadFolder+'audio_feedback_' + new Date().getTime() + '.mp3';
var mp3_file = fs.createWriteStream(mp3File);
mp3_file.on('open', function (fd) {
req.on('data', function(data){
console.log("loading... \n");
mp3_file.write(data);
});
req.on('end', function(){
console.log("finalizing...");
mp3_file.end();
res.writeHead(200, {'Content-Type:' : 'text/plain'});
res.write(mp3File+ ' is written to disk');
res.end('\n');
});
});
}
Hope this helps.
I have fixed it with:
if(requestPath === 'uploadmp3' && req.method === 'POST') {
var mp3 = '';
var mp3File = uploadFolder+'audio_feedback_' + new Date().getTime() + '.mp3';
// req.setEcoding('base64');
req.on('data', function(data){
console.log("loading... \n");
mp3 += data;
});
req.on('end', function(){
console.log("request completed");
fs.open(mp3File, 'w', function(err, fd) {
if(err) {
return console.log(err);
}
// console.log(mp3File + ' file was read...');
fs.writeFile(mp3File, mp3, 'base64', function(err){
if(err) {
return console.log(err);
}
console.log('written to disk: ' + mp3File);
});
});
res.writeHead(200, {'Content-Type:' : 'text/plain'});
res.write(mp3File+ ' is written to disk');
res.end('\n');
});
}
Related
I want to download multiple files from the web using this code:
var fs = require('fs');
var http = require('http');
var request = require('request');
var file;
for(var i = 1; i <= 5; i++) {
//CHECK IF REMOTE FILE EXISTS
request('http://webaddress.com/filename' + i + '.jar', function (err, resp) {
//IF EXISTS DO
if (resp.statusCode == 200) {
//DOWNLOAD DATA AND CREATE A NEW .JAR FILE
file = fs.createWriteStream('D:\\filename' + i + '.jar');
http.get('http://webaddress.com/filename' + i + '.jar', function(response) {
response.pipe(file);
file.on('finish', function() {
file.close();
});
});
}
//FILE DOES NOT EXIST
});
}
The result I want is: multiple files downloaded with filenames filename1-5.jar. The result I am getting is just 1 file with filename filename5.jar (or the last value of the i var in the loop). What am I doing wrong?
Like #Ionut said your requests are async so you need to wait for it
let fs = require('fs');
let request = require('request');
let download = (uri, filename) => {
return new Promise ((resolve, reject) => {
request.head(uri, function(err, res) {
if (res.statusCode === 200) {
request(uri).pipe(fs.createWriteStream(filename)).on('close', resolve);
} else {
reject(res.statusCode);
}
});
});
};
let promises = [];
for(let i = 1; i <= 5; i++) {
promises.push(download('http://webaddress.com/filename' + i + '.jar', 'D:\\filename' + i + '.jar'));
}
Promise.all(promises).then(() => {
process.exit(0);
});
Your request is asynchronous and it will execute only after your loop finishes hence the 5 from the filename. A solution for this is to threat your code separately by creating a new function and call it inside the loop:
var fs = require('fs');
var http = require('http');
var request = require('request');
var file;
function customRequest(i){
//CHECK IF REMOTE FILE EXISTS
return request('http://webaddress.com/filename' + i + '.jar', function(err, resp) {
//IF EXISTS DO
if (resp.statusCode == 200) {
//DOWNLOAD DATA AND CREATE A NEW .JAR FILE
file = fs.createWriteStream('D:\\filename' + i + '.jar');
http.get('http://webaddress.com/filename' + i + '.jar', function(response) {
response.pipe(file);
file.on('finish', function() {
file.close();
});
});
}
//FILE DOES NOT EXIST
});
}
for (var i = 1; i <= 5; i++) {
customRequest(i)
}
I have just started learning to code about 5 days ago and what I'm struggling to achieve, is to have an rssfeed-to-twitter script that posts a shortened url instead of a full website/article feed url. I found a node.js module called TinyURL that could do that but i struggle to get it to work. Here's the full script:
var simpleTwitter = require('simple-twitter');
var fs = require('fs');
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end('RSS Twitter Bot\n');
}).listen(5693);
var timeInterval = 300000; // run every 30m
var timerVar = setInterval (function () {runBot()}, timeInterval);
function runBot(){
var lastCompleted = Date.parse(new Date(0));
console.log(lastCompleted);
try {
var lastcompletedData = fs.readFileSync('./lastCompleted.json', 'utf8');
var timeData = JSON.parse(lastcompletedData);
var lastCompletedFromFile = Date.parse(new Date(timeData.lastCompleted));
if ( isNaN(lastCompletedFromFile) == false ) {
lastCompleted = lastCompletedFromFile;
}
} catch (e) {
console.log(e);
}
fs.readFile('./config.json', 'utf8', function (err, data) {
if (err) console.log(err); // we'll not consider error handling for now
var configData = JSON.parse(data);
console.log(configData);
var twitter = new simpleTwitter( configData.consumerKey //consumer key from twitter api
, configData.consumerSecret //consumer secret key from twitter api
, configData.accessToken //access token from twitter api
, configData.accessTokenSecret //access token secret from twitter api
, 3600);
var dateNow = Date.parse(new Date());
var FeedParser = require('feedparser');
var request = require('request');
var req = request(configData.feedUrl);
var feedparser = new FeedParser();
req.on('error', function (error) {
console.log(error);
});
req.on('response', function (res){
var stream = this;
if (res.statusCode != 200 ) return this.emit('error', new Error('Bad status code'));
stream.pipe(feedparser);
});
feedparser.on('error', function(error) {
console.log(error);
});
feedparser.on('readable', function() {
var stream = this;
var meta = this.meta;
var item;
while (item = stream.read()) {
var itemDate = Date.parse(item.date);
//check to not publish older articles
if (itemDate > lastCompleted){
var titleLength = item.title.length;
var itemTitle = item.title;
var itemLink = item.link;
if (titleLength > 100) {
itemTitle = itemTitle.substring(0, 100);
}
twitter.post('statuses/update'
, {'status' : itemTitle + ' ' + itemLink + " " + configData.tags}
, function (error, data) {
console.dir(data);
});
console.log(itemTitle + ' ' + item.link + configData.tags);
}
}
//TO KNOW WHEN FROM TO START POSTING
var dateCompleted = new Date();
console.log('loop completed at ' + dateCompleted);
var outputData = {
lastCompleted : dateCompleted
}
var outputFilename = './lastCompleted.json';
fs.writeFile(outputFilename, JSON.stringify(outputData, null, 4), function(err) {
if(err) {
console.log(err);
} else {
console.log("JSON saved to " + outputFilename);
}
});
});
});
}
And this is the TinyURL node.js module
var TinyURL = require('tinyurl');
TinyURL.shorten('http://google.com', function(res) {
console.log(res); //Returns a tinyurl
});
Changing the 'http://google.com' string to itemLink var works just fine and prints it in the terminal as expected.
TinyURL.shorten(itemLink, function(res) {
console.log(res); //Returns a tinyurl
});
What i'm trying to achieve is:
twitter.post('statuses/update', {'status' : itemTitle + ' ' + tinyurlLink + " " + configData.tags}
How can i get the response turned into a e.g var tinyurlLink to replace the itemLink var? Any help would be much appreciated!
As suggested by #zerkms sending a tweet from inside the TinyURL.shorten worked!
I'm trying to download a file (+200mb) from an url (that requires to be logged in) using the request module from nodejs but when it finishes the download the server starts to slow down until it crashes or gets really slow.
here's my current code (it downloads the whole file but my server crashes eventually):
//Required modules
var http = require('http'),
url = require("url"),
fs = require('fs'),
request = require('request'),
path = require("path"),
events = require("events"),
j = request.jar(),
request = request.defaults({ jar : j });
// make te request login in with cookies
console.log("downloading file :)");
request({
url:"http://example.com/",
method:"POST",
form:{u: "username",p: "password"}
},
function(error,response,body){
setTimeout(function(){
request
.get('http://example.com/test.ashx?file=15')
.on('error', function(err) {
console.log(err);
})
.pipe(fs.createWriteStream("/var/www/filesDir/CustomName.zip"));
console.log(body);
},1000)
}
);
I've tried applying another solution from this answer but for some reason the file is not being downloaded properly, it only shows "Download progress: 0 bytes" all the time maybe it's something related with the login access.
here I put the other code I'm trying to implement from the last sentence:
var http = require('http');
var fs = require('fs');
var url = require("url");
var request = require('request');
var path = require("path");
var events = require("events");
var j = request.jar();
var request = request.defaults({ jar : j });
request({
url:"http://example.com/",
method:"POST",
form:{u:"username",p:"password"}
}, function(error,response,body){
var downloadfile = "http://example.com/test.ashx?file=15";
var host = url.parse(downloadfile).hostname;
var filename = "1977.zip";
var req = http.request({port: 80, host: host, method: 'GET'});
console.log("Downloading file: " + filename);
console.log("Before download request");
req.end();
dlprogress = 0;
setInterval(function () {
console.log("Download progress: " + dlprogress + " bytes");
}, 1000);
req.addListener('response', function (response) {
var downloadfile = fs.createWriteStream(filename, {'flags': 'a'});
console.log("File size " + filename + ": " + response.headers['content-length'] + " bytes.");
response.addListener('data', function (chunk) {
dlprogress += chunk.length;
downloadfile.write(chunk, encoding='binary');
});
response.addListener("end", function() {
downloadfile.end();
console.log("Finished downloading " + filename);
});
});
}
);
It doesn't matter which way you decide to help me with.
I ended up doing it like this, I've tested the code multiple times and the server didn't crash anymore:
var request = require('request');
var filed = require('filed');
var j = request.jar();
var request = request.defaults({ jar : j });
// make the request and login
request({
url: "http://example.com/login",
method:"POST",
// 'u' and 'p' are the field names on the form
form:{u:"username",p:"password"}
}, function(error,response,body){
setTimeout(function(){
var downloadURL = 'http://example.com/download/file.zip';
var downloadPath = "/path/to/download/localNameForFile.zip";
var downloadFile = filed(downloadPath);
var r = request(downloadURL).pipe(downloadFile);
r.on('data', function(data) {
console.log('binary data received');
});
downloadFile.on('end', function () {
console.log(downloadPath, 'file downloaded to path');
});
downloadFile.on('error', function (err) {
console.log(err, 'error downloading file');
});
},3000)
}
);
I have the following middleware function
var bodyParser = require('body-parser'),
fs = require('fs');
module.exports = function(req, res, next) {
// Add paths to this array to allow binary uploads
var pathsAllowingBinaryBody = [
'/api2/information/upload',
'/api2/kpi/upload',
];
if (pathsAllowingBinaryBody.indexOf(req._parsedUrl.pathname) !== -1) {
var date = new Date();
req.filePath = "uploads/" + date.getTime() + "_" + date.getMilliseconds() + "_" + Math.floor(Math.random() * 1000000000) + "_" + parseInt(req.headers['content-length']);
var writeStream = fs.createWriteStream(req.filePath);
req.on('data', function(chunk) {
writeStream.write(chunk);
});
req.on('end', function() {
writeStream.end();
next();
});
} else {
bodyParser.json()(req, res, next);
}
};
The files is being transfered correctly however sadly the next() in the
req.on('end', function() {
writeStream.end();
next();
});
is called before it is done writing all data to the new file.
My question is what am i doing wrong? And how can i fix it?
Use the writable file stream's close event to know when the file descriptor has been closed.
Replace this:
var writeStream = fs.createWriteStream(req.filePath);
req.on('data', function(chunk) {
writeStream.write(chunk);
});
req.on('end', function() {
writeStream.end();
next();
});
with this:
req.pipe(fs.createWriteStream(req.filePath)).on('close', next);
I want to send a video file to the client and display the video with .createObjectURL().
Node server.js:
var fs = require("fs"),
http = require("http");
http.createServer(function (req, res) {
if (req.url == "/") {
res.writeHead(200, { "Content-Type": "text/html" });
res.end('<video id="video" src="" autoplay controls loop width="200px" height="200px" muted></video>' +
'<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>' +
'<script src="blobvideo.js"></script>');
}
else if (req.url == "/blobvideo.js") {
res.writeHead(200, { "Content-Type": "application/javascript" });
fs.readFile('./blobvideo.js', function(err, data) {
res.end(data.toString());
});
}
else if (req.url == "/video") {
fs.readFile('video.mp4', function(err, data) {
res.end(data);
});
}
}).listen(3000);
Client blobvideo.js:
$.ajax( "/video" ).done(function(data) {
var ab = new ArrayBuffer(data.length);
var view = new Uint8Array(ab);
for(var i = 0; i < data.length; ++i) {
view[i] = data[i];
}
blob = new Blob([ab], { type: "video/mp4" });
document.getElementById("video").src = (window.URL || window.webkitURL).createObjectURL(blob);
});
In this code, the video is sent all in one piece, and the video doesn't play. My questions:
How can I fix this to play the video?
How can I change it to stream the file rather than wait for the entire video to download?
Edit for Clarification
I want to use Blob and .createObjectURL() on the client because I am trying to build a peer-to-peer video implementation of the WebRTC RTCPeerConnection, so that static video data can be sent from the client to another client without sending it through the server.
This is pure nodejs javascript which streams video/audio without outside library dependencies and requires NO client code ... launch it using :
node this_code.js
then point your client browser at
http://localhost:8888
Huge benefit is the browser client video rendering UI widgets just work - (ability to jump to some random media location, etc.)
var http = require('http'),
fs = require('fs'),
util = require('util');
// put any audio or video file here
var path = "/path/to/audio/or/video/file/local/to/server/cool.mp4";
var port = 8888;
var host = "localhost";
http.createServer(function (req, res) {
var stat = fs.statSync(path);
var total = stat.size;
if (req.headers.range) {
// meaning client (browser) has moved the forward/back slider
// which has sent this request back to this server logic ... cool
var range = req.headers.range;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;
var chunksize = (end-start)+1;
console.log('RANGE: ' + start + ' - ' + end + ' = ' + chunksize);
var file = fs.createReadStream(path, {start: start, end: end});
res.writeHead(206, { 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/mp4' });
file.pipe(res);
} else {
console.log('ALL: ' + total);
res.writeHead(200, { 'Content-Length': total, 'Content-Type': 'video/mp4' });
fs.createReadStream(path).pipe(res);
}
}).listen(port, host);
console.log("Server running at http://" + host + ":" + port + "/");
enjoy,
I would just serve video.mp4 as a static asset and set the src of the video element to the URL for that video.